1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,fuchsia.HandleChecker -analyzer-output=text \
2 // RUN:     -verify %s
3 
4 typedef __typeof__(sizeof(int)) size_t;
5 typedef int zx_status_t;
6 typedef __typeof__(sizeof(int)) zx_handle_t;
7 typedef unsigned int uint32_t;
8 #define NULL ((void *)0)
9 #define ZX_HANDLE_INVALID 0
10 
11 #if defined(__clang__)
12 #define ZX_HANDLE_ACQUIRE  __attribute__((acquire_handle("Fuchsia")))
13 #define ZX_HANDLE_RELEASE  __attribute__((release_handle("Fuchsia")))
14 #define ZX_HANDLE_USE  __attribute__((use_handle("Fuchsia")))
15 #else
16 #define ZX_HANDLE_ACQUIRE
17 #define ZX_HANDLE_RELEASE
18 #define ZX_HANDLE_USE
19 #endif
20 
21 zx_status_t zx_channel_create(
22     uint32_t options,
23     zx_handle_t *out0 ZX_HANDLE_ACQUIRE,
24     zx_handle_t *out1 ZX_HANDLE_ACQUIRE);
25 
26 zx_status_t zx_handle_close(
27     zx_handle_t handle ZX_HANDLE_RELEASE);
28 
29 void escape1(zx_handle_t *in);
30 void escape2(zx_handle_t in);
31 void (*escape3)(zx_handle_t) = escape2;
32 
33 void use1(const zx_handle_t *in ZX_HANDLE_USE);
34 void use2(zx_handle_t in ZX_HANDLE_USE);
35 
36 void moreArgs(zx_handle_t, int, ...);
37 void lessArgs(zx_handle_t, int a = 5);
38 
39 // To test if argument indexes are OK for operator calls.
40 struct MyType {
41   ZX_HANDLE_ACQUIRE
42   zx_handle_t operator+(zx_handle_t ZX_HANDLE_RELEASE replace);
43 };
44 
45 void checkInvalidHandle01() {
46   zx_handle_t sa, sb;
47   zx_channel_create(0, &sa, &sb);
48   if (sa == ZX_HANDLE_INVALID)
49     ;
50   // Will we ever see a warning like below?
51   // We eagerly replace the symbol with a constant and lose info...
52   use2(sa); // TODOexpected-warning {{Use of an invalid handle}}
53   zx_handle_close(sb);
54   zx_handle_close(sa);
55 }
56 
57 void checkInvalidHandle2() {
58   zx_handle_t sa, sb;
59   zx_channel_create(0, &sa, &sb);
60   if (sb != ZX_HANDLE_INVALID)
61     zx_handle_close(sb);
62   if (sa != ZX_HANDLE_INVALID)
63     zx_handle_close(sa);
64 }
65 
66 void checkNoCrash01() {
67   zx_handle_t sa, sb;
68   zx_channel_create(0, &sa, &sb);
69   moreArgs(sa, 1, 2, 3, 4, 5);
70   lessArgs(sa);
71   zx_handle_close(sa);
72   zx_handle_close(sb);
73 }
74 
75 void checkNoLeak01() {
76   zx_handle_t sa, sb;
77   zx_channel_create(0, &sa, &sb);
78   zx_handle_close(sa);
79   zx_handle_close(sb);
80 }
81 
82 void checkNoLeak02() {
83   zx_handle_t ay[2];
84   zx_channel_create(0, &ay[0], &ay[1]);
85   zx_handle_close(ay[0]);
86   zx_handle_close(ay[1]);
87 }
88 
89 void checkNoLeak03() {
90   zx_handle_t ay[2];
91   zx_channel_create(0, &ay[0], &ay[1]);
92   for (int i = 0; i < 2; i++)
93     zx_handle_close(ay[i]);
94 }
95 
96 zx_handle_t checkNoLeak04() {
97   zx_handle_t sa, sb;
98   zx_channel_create(0, &sa, &sb);
99   zx_handle_close(sa);
100   return sb; // no warning
101 }
102 
103 zx_handle_t checkNoLeak05(zx_handle_t *out1) {
104   zx_handle_t sa, sb;
105   zx_channel_create(0, &sa, &sb);
106   *out1 = sa;
107   return sb; // no warning
108 }
109 
110 void checkNoLeak06() {
111   zx_handle_t sa, sb;
112   if (zx_channel_create(0, &sa, &sb))
113     return;
114   zx_handle_close(sa);
115   zx_handle_close(sb);
116 }
117 
118 void checkLeak01(int tag) {
119   zx_handle_t sa, sb;
120   if (zx_channel_create(0, &sa, &sb)) // expected-note    {{Handle allocated here}}
121     return;                           // expected-note@-1 {{Assuming the condition is false}}
122                                       // expected-note@-2 {{Taking false branch}}
123   use1(&sa);
124   if (tag) // expected-note {{Assuming 'tag' is 0}}
125     zx_handle_close(sa);
126   // expected-note@-2 {{Taking false branch}}
127   use2(sb); // expected-warning {{Potential leak of handle}}
128   // expected-note@-1 {{Potential leak of handle}}
129   zx_handle_close(sb);
130 }
131 
132 void checkReportLeakOnOnePath(int tag) {
133   zx_handle_t sa, sb;
134   if (zx_channel_create(0, &sa, &sb)) // expected-note {{Handle allocated here}}
135     return;                           // expected-note@-1 {{Assuming the condition is false}}
136                                       // expected-note@-2 {{Taking false branch}}
137   zx_handle_close(sb);
138   switch(tag) { // expected-note {{Control jumps to the 'default' case at line}}
139     case 0:
140       use2(sa);
141       return;
142     case 1:
143       use2(sa);
144       return;
145     case 2:
146       use2(sa);
147       return;
148     case 3:
149       use2(sa);
150       return;
151     case 4:
152       use2(sa);
153       return;
154     default:
155       use2(sa);
156       return; // expected-warning {{Potential leak of handle}}
157               // expected-note@-1 {{Potential leak of handle}}
158   }
159 }
160 
161 void checkDoubleRelease01(int tag) {
162   zx_handle_t sa, sb;
163   zx_channel_create(0, &sa, &sb);
164   // expected-note@-1 {{Handle allocated here}}
165   if (tag) // expected-note {{Assuming 'tag' is not equal to 0}}
166     zx_handle_close(sa); // expected-note {{Handle released here}}
167   // expected-note@-2 {{Taking true branch}}
168   zx_handle_close(sa); // expected-warning {{Releasing a previously released handle}}
169   // expected-note@-1 {{Releasing a previously released handle}}
170   zx_handle_close(sb);
171 }
172 
173 void checkUseAfterFree01(int tag) {
174   zx_handle_t sa, sb;
175   zx_channel_create(0, &sa, &sb);
176   // expected-note@-1 {{Handle allocated here}}
177   // expected-note@-2 {{Handle allocated here}}
178   // expected-note@+2 {{Taking true branch}}
179   // expected-note@+1 {{Taking false branch}}
180   if (tag) {
181     // expected-note@-1 {{Assuming 'tag' is not equal to 0}}
182     zx_handle_close(sa); // expected-note {{Handle released here}}
183     use1(&sa); // expected-warning {{Using a previously released handle}}
184     // expected-note@-1 {{Using a previously released handle}}
185   }
186   // expected-note@-6 {{Assuming 'tag' is 0}}
187   zx_handle_close(sb); // expected-note {{Handle released here}}
188   use2(sb); // expected-warning {{Using a previously released handle}}
189   // expected-note@-1 {{Using a previously released handle}}
190 }
191 
192 void checkMemberOperatorIndices() {
193   zx_handle_t sa, sb, sc;
194   zx_channel_create(0, &sa, &sb);
195   zx_handle_close(sb);
196   MyType t;
197   sc = t + sa;
198   zx_handle_close(sc);
199 }
200 
201 // RAII
202 
203 template <typename T>
204 struct HandleWrapper {
205   ~HandleWrapper() { close(); }
206   void close() {
207     if (handle != ZX_HANDLE_INVALID)
208       zx_handle_close(handle);
209   }
210   T *get_handle_address() { return &handle; }
211 private:
212   T handle;
213 };
214 
215 void doNotWarnOnRAII() {
216   HandleWrapper<zx_handle_t> w1;
217   zx_handle_t sb;
218   if (zx_channel_create(0, w1.get_handle_address(), &sb))
219     return;
220   zx_handle_close(sb);
221 }
222 
223 template <typename T>
224 struct HandleWrapperUnkonwDtor {
225   ~HandleWrapperUnkonwDtor();
226   void close() {
227     if (handle != ZX_HANDLE_INVALID)
228       zx_handle_close(handle);
229   }
230   T *get_handle_address() { return &handle; }
231 private:
232   T handle;
233 };
234 
235 void doNotWarnOnUnkownDtor() {
236   HandleWrapperUnkonwDtor<zx_handle_t> w1;
237   zx_handle_t sb;
238   if (zx_channel_create(0, w1.get_handle_address(), &sb))
239     return;
240   zx_handle_close(sb);
241 }
242 
243 // Various escaping scenarios
244 
245 zx_handle_t *get_handle_address();
246 
247 void escape_store_to_escaped_region01() {
248   zx_handle_t sb;
249   if (zx_channel_create(0, get_handle_address(), &sb))
250     return;
251   zx_handle_close(sb);
252 }
253 
254 struct object {
255   zx_handle_t *get_handle_address();
256 };
257 
258 void escape_store_to_escaped_region02(object &o) {
259   zx_handle_t sb;
260   // Same as above.
261   if (zx_channel_create(0, o.get_handle_address(), &sb))
262     return;
263   zx_handle_close(sb);
264 }
265 
266 void escape_store_to_escaped_region03(object o) {
267   zx_handle_t sb;
268   // Should we consider the pointee of get_handle_address escaped?
269   // Maybe we only should it consider escaped if o escapes?
270   if (zx_channel_create(0, o.get_handle_address(), &sb))
271     return;
272   zx_handle_close(sb);
273 }
274 
275 void escape_through_call(int tag) {
276   zx_handle_t sa, sb;
277   if (zx_channel_create(0, &sa, &sb))
278     return;
279   escape1(&sa);
280   if (tag)
281     escape2(sb);
282   else
283     escape3(sb);
284 }
285 
286 struct have_handle {
287   zx_handle_t h;
288   zx_handle_t *hp;
289 };
290 
291 void escape_through_store01(have_handle *handle) {
292   zx_handle_t sa;
293   if (zx_channel_create(0, &sa, handle->hp))
294     return;
295   handle->h = sa;
296 }
297 
298 have_handle global;
299 void escape_through_store02() {
300   zx_handle_t sa;
301   if (zx_channel_create(0, &sa, global.hp))
302     return;
303   global.h = sa;
304 }
305 
306 have_handle escape_through_store03() {
307   zx_handle_t sa, sb;
308   if (zx_channel_create(0, &sa, &sb))
309     return {0, nullptr};
310   zx_handle_close(sb);
311   return {sa, nullptr};
312 }
313 
314 void escape_structs(have_handle *);
315 void escape_transitively01() {
316   zx_handle_t sa, sb;
317   if (zx_channel_create(0, &sa, &sb))
318     return;
319   have_handle hs[2];
320   hs[1] = {sa, &sb};
321   escape_structs(hs);
322 }
323 
324 void escape_top_level_pointees(zx_handle_t *h) {
325   zx_handle_t h2;
326   if (zx_channel_create(0, h, &h2))
327     return;
328   zx_handle_close(h2);
329 } // *h should be escaped here. Right?
330