1 // RUN: %clang_analyze_cc1 -std=c++14 \
2 // RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
3 // RUN:  -analyzer-output=text -verify -DDEFAULT_TRIPLE %s 2>&1 | FileCheck %s -check-prefix=DEFAULT-CHECK
4 //
5 // RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \
6 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
7 // RUN: -analyzer-output=text -verify -DAMDGCN_TRIPLE %s 2>&1 | FileCheck %s -check-prefix=AMDGCN-CHECK
8 
9 #include "Inputs/llvm.h"
10 
11 // The amggcn triple case uses an intentionally different address space.
12 // The core.NullDereference checker intentionally ignores checks
13 // that use address spaces, so the case is differentiated here.
14 //
15 // From https://llvm.org/docs/AMDGPUUsage.html#address-spaces,
16 // select address space 3 (local), since the pointer size is
17 // different than Generic.
18 #define DEVICE __attribute__((address_space(3)))
19 
20 namespace clang {
21 struct Shape {
22   template <typename T>
23   const T *castAs() const;
24 
25   template <typename T>
26   const T *getAs() const;
27 };
28 class Triangle : public Shape {};
29 class Rectangle : public Shape {};
30 class Hexagon : public Shape {};
31 class Circle : public Shape {};
32 } // namespace clang
33 
34 using namespace llvm;
35 using namespace clang;
36 
37 void clang_analyzer_printState();
38 
39 #if defined(DEFAULT_TRIPLE)
40 void evalReferences(const Shape &S) {
41   const auto &C = dyn_cast<Circle>(S);
42   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
43   // expected-note@-2 {{Dereference of null pointer}}
44   // expected-warning@-3 {{Dereference of null pointer}}
45   clang_analyzer_printState();
46   // DEFAULT-CHECK: "dynamic_types": [
47   // DEFAULT-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const class clang::Circle &", "sub_classable": true }
48   (void)C;
49 }
50 #elif defined(AMDGCN_TRIPLE)
51 void evalReferences(const Shape &S) {
52   const auto &C = dyn_cast<DEVICE Circle>(S);
53   clang_analyzer_printState();
54   // AMDGCN-CHECK: "dynamic_types": [
55   // AMDGCN-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }
56   (void)C;
57 }
58 #else
59 #error Target must be specified, and must be pinned
60 #endif
61 
62 void evalNonNullParamNonNullReturnReference(const Shape &S) {
63   const auto *C = dyn_cast_or_null<Circle>(S);
64   // expected-note@-1 {{'C' initialized here}}
65 
66   if (!dyn_cast_or_null<Circle>(C)) {
67     // expected-note@-1 {{'C' is a 'Circle'}}
68     // expected-note@-2 {{Taking false branch}}
69     return;
70   }
71 
72   if (dyn_cast_or_null<Triangle>(C)) {
73     // expected-note@-1 {{Assuming 'C' is not a 'Triangle'}}
74     // expected-note@-2 {{Taking false branch}}
75     return;
76   }
77 
78   if (dyn_cast_or_null<Rectangle>(C)) {
79     // expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
80     // expected-note@-2 {{Taking false branch}}
81     return;
82   }
83 
84   if (dyn_cast_or_null<Hexagon>(C)) {
85     // expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
86     // expected-note@-2 {{Taking false branch}}
87     return;
88   }
89 
90   if (isa<Triangle>(C)) {
91     // expected-note@-1 {{'C' is not a 'Triangle'}}
92     // expected-note@-2 {{Taking false branch}}
93     return;
94   }
95 
96   if (isa<Triangle, Rectangle>(C)) {
97     // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}}
98     // expected-note@-2 {{Taking false branch}}
99     return;
100   }
101 
102   if (isa<Triangle, Rectangle, Hexagon>(C)) {
103     // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}}
104     // expected-note@-2 {{Taking false branch}}
105     return;
106   }
107 
108   if (isa<Circle, Rectangle, Hexagon>(C)) {
109     // expected-note@-1 {{'C' is a 'Circle'}}
110     // expected-note@-2 {{Taking true branch}}
111 
112     (void)(1 / !C);
113     // expected-note@-1 {{'C' is non-null}}
114     // expected-note@-2 {{Division by zero}}
115     // expected-warning@-3 {{Division by zero}}
116   }
117 }
118 
119 void evalNonNullParamNonNullReturn(const Shape *S) {
120   const auto *C = cast<Circle>(S);
121   // expected-note@-1 {{'S' is a 'Circle'}}
122   // expected-note@-2 {{'C' initialized here}}
123 
124   if (!dyn_cast_or_null<Circle>(C)) {
125     // expected-note@-1 {{'C' is a 'Circle'}}
126     // expected-note@-2 {{Taking false branch}}
127     return;
128   }
129 
130   if (dyn_cast_or_null<Triangle>(C)) {
131     // expected-note@-1 {{Assuming 'C' is not a 'Triangle'}}
132     // expected-note@-2 {{Taking false branch}}
133     return;
134   }
135 
136   if (dyn_cast_or_null<Rectangle>(C)) {
137     // expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
138     // expected-note@-2 {{Taking false branch}}
139     return;
140   }
141 
142   if (dyn_cast_or_null<Hexagon>(C)) {
143     // expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
144     // expected-note@-2 {{Taking false branch}}
145     return;
146   }
147 
148   if (isa<Triangle>(C)) {
149     // expected-note@-1 {{'C' is not a 'Triangle'}}
150     // expected-note@-2 {{Taking false branch}}
151     return;
152   }
153 
154   if (isa<Triangle, Rectangle>(C)) {
155     // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}}
156     // expected-note@-2 {{Taking false branch}}
157     return;
158   }
159 
160   if (isa<Triangle, Rectangle, Hexagon>(C)) {
161     // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}}
162     // expected-note@-2 {{Taking false branch}}
163     return;
164   }
165 
166   if (isa<Circle, Rectangle, Hexagon>(C)) {
167     // expected-note@-1 {{'C' is a 'Circle'}}
168     // expected-note@-2 {{Taking true branch}}
169 
170     (void)(1 / !C);
171     // expected-note@-1 {{'C' is non-null}}
172     // expected-note@-2 {{Division by zero}}
173     // expected-warning@-3 {{Division by zero}}
174   }
175 }
176 
177 void evalNonNullParamNullReturn(const Shape *S) {
178   const auto *C = dyn_cast_or_null<Circle>(S);
179   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
180 
181   if (const auto *T = dyn_cast_or_null<Triangle>(S)) {
182     // expected-note@-1 {{Assuming 'S' is a 'Triangle'}}
183     // expected-note@-2 {{'T' initialized here}}
184     // expected-note@-3 {{'T' is non-null}}
185     // expected-note@-4 {{Taking true branch}}
186 
187     (void)(1 / !T);
188     // expected-note@-1 {{'T' is non-null}}
189     // expected-note@-2 {{Division by zero}}
190     // expected-warning@-3 {{Division by zero}}
191   }
192 }
193 
194 void evalNullParamNullReturn(const Shape *S) {
195   const auto *C = dyn_cast_or_null<Circle>(S);
196   // expected-note@-1 {{Assuming null pointer is passed into cast}}
197   // expected-note@-2 {{'C' initialized to a null pointer value}}
198 
199   (void)(1 / (bool)C);
200   // expected-note@-1 {{Division by zero}}
201   // expected-warning@-2 {{Division by zero}}
202 }
203 
204 void evalZeroParamNonNullReturnPointer(const Shape *S) {
205   const auto *C = S->castAs<Circle>();
206   // expected-note@-1 {{'S' is a 'Circle'}}
207   // expected-note@-2 {{'C' initialized here}}
208 
209   (void)(1 / !C);
210   // expected-note@-1 {{'C' is non-null}}
211   // expected-note@-2 {{Division by zero}}
212   // expected-warning@-3 {{Division by zero}}
213 }
214 
215 void evalZeroParamNonNullReturn(const Shape &S) {
216   const auto *C = S.castAs<Circle>();
217   // expected-note@-1 {{'C' initialized here}}
218 
219   (void)(1 / !C);
220   // expected-note@-1 {{'C' is non-null}}
221   // expected-note@-2 {{Division by zero}}
222   // expected-warning@-3 {{Division by zero}}
223 }
224 
225 void evalZeroParamNullReturn(const Shape *S) {
226   const auto &C = S->getAs<Circle>();
227   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
228   // expected-note@-2 {{Storing null pointer value}}
229   // expected-note@-3 {{'C' initialized here}}
230 
231   if (!dyn_cast_or_null<Triangle>(S)) {
232     // expected-note@-1 {{Assuming 'S' is a 'Triangle'}}
233     // expected-note@-2 {{Taking false branch}}
234     return;
235   }
236 
237   if (!dyn_cast_or_null<Triangle>(S)) {
238     // expected-note@-1 {{'S' is a 'Triangle'}}
239     // expected-note@-2 {{Taking false branch}}
240     return;
241   }
242 
243   (void)(1 / (bool)C);
244   // expected-note@-1 {{Division by zero}}
245   // expected-warning@-2 {{Division by zero}}
246 }
247