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 ZX_HANDLE_ACQUIRE
30 zx_handle_t return_handle();
31 
32 void escape1(zx_handle_t *in);
33 void escape2(zx_handle_t in);
34 void (*escape3)(zx_handle_t) = escape2;
35 
36 void use1(const zx_handle_t *in ZX_HANDLE_USE);
37 void use2(zx_handle_t in ZX_HANDLE_USE);
38 
39 void moreArgs(zx_handle_t, int, ...);
40 void lessArgs(zx_handle_t, int a = 5);
41 
42 // To test if argument indexes are OK for operator calls.
43 struct MyType {
44   ZX_HANDLE_ACQUIRE
45   zx_handle_t operator+(zx_handle_t ZX_HANDLE_RELEASE replace);
46 };
47 
48 void checkInvalidHandle01() {
49   zx_handle_t sa, sb;
50   zx_channel_create(0, &sa, &sb);
51   if (sa == ZX_HANDLE_INVALID)
52     ;
53   // Will we ever see a warning like below?
54   // We eagerly replace the symbol with a constant and lose info...
55   use2(sa); // TODOexpected-warning {{Use of an invalid handle}}
56   zx_handle_close(sb);
57   zx_handle_close(sa);
58 }
59 
60 void checkInvalidHandle2() {
61   zx_handle_t sa, sb;
62   zx_channel_create(0, &sa, &sb);
63   if (sb != ZX_HANDLE_INVALID)
64     zx_handle_close(sb);
65   if (sa != ZX_HANDLE_INVALID)
66     zx_handle_close(sa);
67 }
68 
69 void handleDieBeforeErrorSymbol01() {
70   zx_handle_t sa, sb;
71   zx_status_t status = zx_channel_create(0, &sa, &sb);
72   if (status < 0)
73     return;
74   __builtin_trap();
75 }
76 
77 void handleDieBeforeErrorSymbol02() {
78   zx_handle_t sa, sb;
79   zx_status_t status = zx_channel_create(0, &sa, &sb);
80   // FIXME: There appears to be non-determinism in choosing
81   // which handle to report.
82   // expected-note-re@-3 {{Handle allocated through {{(2nd|3rd)}} parameter}}
83   if (status == 0) { // expected-note {{Assuming 'status' is equal to 0}}
84                      // expected-note@-1 {{Taking true branch}}
85     return;          // expected-warning {{Potential leak of handle}}
86                      // expected-note@-1 {{Potential leak of handle}}
87   }
88   __builtin_trap();
89 }
90 
91 void checkNoCrash01() {
92   zx_handle_t sa, sb;
93   zx_channel_create(0, &sa, &sb);
94   moreArgs(sa, 1, 2, 3, 4, 5);
95   lessArgs(sa);
96   zx_handle_close(sa);
97   zx_handle_close(sb);
98 }
99 
100 void checkNoLeak01() {
101   zx_handle_t sa, sb;
102   zx_channel_create(0, &sa, &sb);
103   zx_handle_close(sa);
104   zx_handle_close(sb);
105 }
106 
107 void checkNoLeak02() {
108   zx_handle_t ay[2];
109   zx_channel_create(0, &ay[0], &ay[1]);
110   zx_handle_close(ay[0]);
111   zx_handle_close(ay[1]);
112 }
113 
114 void checkNoLeak03() {
115   zx_handle_t ay[2];
116   zx_channel_create(0, &ay[0], &ay[1]);
117   for (int i = 0; i < 2; i++)
118     zx_handle_close(ay[i]);
119 }
120 
121 zx_handle_t checkNoLeak04() {
122   zx_handle_t sa, sb;
123   zx_channel_create(0, &sa, &sb);
124   zx_handle_close(sa);
125   return sb; // no warning
126 }
127 
128 zx_handle_t checkNoLeak05(zx_handle_t *out1) {
129   zx_handle_t sa, sb;
130   zx_channel_create(0, &sa, &sb);
131   *out1 = sa;
132   return sb; // no warning
133 }
134 
135 void checkNoLeak06() {
136   zx_handle_t sa, sb;
137   if (zx_channel_create(0, &sa, &sb))
138     return;
139   zx_handle_close(sa);
140   zx_handle_close(sb);
141 }
142 
143 void checkLeak01(int tag) {
144   zx_handle_t sa, sb;
145   if (zx_channel_create(0, &sa, &sb)) // expected-note    {{Handle allocated through 2nd parameter}}
146     return;                           // expected-note@-1 {{Assuming the condition is false}}
147                                       // expected-note@-2 {{Taking false branch}}
148   use1(&sa);
149   if (tag) // expected-note {{Assuming 'tag' is 0}}
150     zx_handle_close(sa);
151   // expected-note@-2 {{Taking false branch}}
152   use2(sb); // expected-warning {{Potential leak of handle}}
153   // expected-note@-1 {{Potential leak of handle}}
154   zx_handle_close(sb);
155 }
156 
157 void checkLeakFromReturn01(int tag) {
158   zx_handle_t sa = return_handle(); // expected-note {{Function 'return_handle' returns an open handle}}
159   (void)sa;
160 } // expected-note {{Potential leak of handle}}
161 // expected-warning@-1 {{Potential leak of handle}}
162 
163 void checkReportLeakOnOnePath(int tag) {
164   zx_handle_t sa, sb;
165   if (zx_channel_create(0, &sa, &sb)) // expected-note {{Handle allocated through 2nd parameter}}
166     return;                           // expected-note@-1 {{Assuming the condition is false}}
167                                       // expected-note@-2 {{Taking false branch}}
168   zx_handle_close(sb);
169   switch (tag) { // expected-note {{Control jumps to the 'default' case at line}}
170   case 0:
171     use2(sa);
172     return;
173   case 1:
174     use2(sa);
175     return;
176   case 2:
177     use2(sa);
178     return;
179   case 3:
180     use2(sa);
181     return;
182   case 4:
183     use2(sa);
184     return;
185   default:
186     use2(sa);
187     return; // expected-warning {{Potential leak of handle}}
188             // expected-note@-1 {{Potential leak of handle}}
189   }
190 }
191 
192 void checkDoubleRelease01(int tag) {
193   zx_handle_t sa, sb;
194   zx_channel_create(0, &sa, &sb);
195   // expected-note@-1 {{Handle allocated through 2nd parameter}}
196   if (tag)               // expected-note {{Assuming 'tag' is not equal to 0}}
197     zx_handle_close(sa); // expected-note {{Handle released through 1st parameter}}
198   // expected-note@-2 {{Taking true branch}}
199   zx_handle_close(sa); // expected-warning {{Releasing a previously released handle}}
200   // expected-note@-1 {{Releasing a previously released handle}}
201   zx_handle_close(sb);
202 }
203 
204 void checkUseAfterFree01(int tag) {
205   zx_handle_t sa, sb;
206   zx_channel_create(0, &sa, &sb);
207   // expected-note@-1 {{Handle allocated through 2nd parameter}}
208   // expected-note@-2 {{Handle allocated through 3rd parameter}}
209   // expected-note@+2 {{Taking true branch}}
210   // expected-note@+1 {{Taking false branch}}
211   if (tag) {
212     // expected-note@-1 {{Assuming 'tag' is not equal to 0}}
213     zx_handle_close(sa); // expected-note {{Handle released through 1st parameter}}
214     use1(&sa);           // expected-warning {{Using a previously released handle}}
215     // expected-note@-1 {{Using a previously released handle}}
216   }
217   // expected-note@-6 {{Assuming 'tag' is 0}}
218   zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}}
219   use2(sb);            // expected-warning {{Using a previously released handle}}
220   // expected-note@-1 {{Using a previously released handle}}
221 }
222 
223 void checkMemberOperatorIndices() {
224   zx_handle_t sa, sb, sc;
225   zx_channel_create(0, &sa, &sb);
226   zx_handle_close(sb);
227   MyType t;
228   sc = t + sa;
229   zx_handle_close(sc);
230 }
231 
232 struct HandleStruct {
233   zx_handle_t h;
234 };
235 
236 void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE);
237 
238 void use_handle_struct(HandleStruct hs ZX_HANDLE_USE);
239 
240 void checkHandleInStructureUseAfterFree() {
241   zx_handle_t sa, sb;
242   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
243   HandleStruct hs;
244   hs.h = sb;
245   use_handle_struct(hs);
246   close_handle_struct(hs); // expected-note {{Handle released through 1st parameter}}
247   zx_handle_close(sa);
248 
249   use2(sb); // expected-warning {{Using a previously released handle}}
250   // expected-note@-1 {{Using a previously released handle}}
251 }
252 
253 void checkHandleInStructureUseAfterFree2() {
254   zx_handle_t sa, sb;
255   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
256   HandleStruct hs;
257   hs.h = sb;
258   use_handle_struct(hs);
259   zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}}
260   zx_handle_close(sa);
261 
262   use_handle_struct(hs); // expected-warning {{Using a previously released handle}}
263   // expected-note@-1 {{Using a previously released handle}}
264 }
265 
266 void checkHandleInStructureLeak() {
267   zx_handle_t sa, sb;
268   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
269   HandleStruct hs;
270   hs.h = sb;
271   zx_handle_close(sa); // expected-warning {{Potential leak of handle}}
272   // expected-note@-1 {{Potential leak of handle}}
273 }
274 
275 struct HandlePtrStruct {
276   zx_handle_t *h;
277 };
278 
279 void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE);
280 
281 void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE);
282 
283 void checkHandlePtrInStructureUseAfterFree() {
284   zx_handle_t sa, sb;
285   zx_channel_create(0, &sa, &sb);
286   HandlePtrStruct hs;
287   hs.h = &sb;
288   use_handle_struct(hs);
289   close_handle_struct(hs); // expected-note {{Handle released through 1st parameter}}
290   zx_handle_close(sa);
291 
292   use2(sb); // expected-warning {{Using a previously released handle}}
293   // expected-note@-1 {{Using a previously released handle}}
294 }
295 
296 void checkHandlePtrInStructureUseAfterFree2() {
297   zx_handle_t sa, sb;
298   zx_channel_create(0, &sa, &sb);
299   HandlePtrStruct hs;
300   hs.h = &sb;
301   use_handle_struct(hs);
302   zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}}
303   zx_handle_close(sa);
304 
305   use_handle_struct(hs); // expected-warning {{Using a previously released handle}}
306   // expected-note@-1 {{Using a previously released handle}}
307 }
308 
309 void checkHandlePtrInStructureLeak() {
310   zx_handle_t sa, sb;
311   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
312   HandlePtrStruct hs;
313   hs.h = &sb;
314   zx_handle_close(sa); // expected-warning {{Potential leak of handle}}
315   // expected-note@-1 {{Potential leak of handle}}
316 }
317 
318 // RAII
319 
320 template <typename T>
321 struct HandleWrapper {
322   ~HandleWrapper() { close(); }
323   void close() {
324     if (handle != ZX_HANDLE_INVALID)
325       zx_handle_close(handle);
326   }
327   T *get_handle_address() { return &handle; }
328 
329 private:
330   T handle;
331 };
332 
333 void doNotWarnOnRAII() {
334   HandleWrapper<zx_handle_t> w1;
335   zx_handle_t sb;
336   if (zx_channel_create(0, w1.get_handle_address(), &sb))
337     return;
338   zx_handle_close(sb);
339 }
340 
341 template <typename T>
342 struct HandleWrapperUnkonwDtor {
343   ~HandleWrapperUnkonwDtor();
344   void close() {
345     if (handle != ZX_HANDLE_INVALID)
346       zx_handle_close(handle);
347   }
348   T *get_handle_address() { return &handle; }
349 
350 private:
351   T handle;
352 };
353 
354 void doNotWarnOnUnknownDtor() {
355   HandleWrapperUnkonwDtor<zx_handle_t> w1;
356   zx_handle_t sb;
357   if (zx_channel_create(0, w1.get_handle_address(), &sb))
358     return;
359   zx_handle_close(sb);
360 }
361 
362 // Various escaping scenarios
363 
364 zx_handle_t *get_handle_address();
365 
366 void escape_store_to_escaped_region01() {
367   zx_handle_t sb;
368   if (zx_channel_create(0, get_handle_address(), &sb))
369     return;
370   zx_handle_close(sb);
371 }
372 
373 struct object {
374   zx_handle_t *get_handle_address();
375 };
376 
377 void escape_store_to_escaped_region02(object &o) {
378   zx_handle_t sb;
379   // Same as above.
380   if (zx_channel_create(0, o.get_handle_address(), &sb))
381     return;
382   zx_handle_close(sb);
383 }
384 
385 void escape_store_to_escaped_region03(object o) {
386   zx_handle_t sb;
387   // Should we consider the pointee of get_handle_address escaped?
388   // Maybe we only should it consider escaped if o escapes?
389   if (zx_channel_create(0, o.get_handle_address(), &sb))
390     return;
391   zx_handle_close(sb);
392 }
393 
394 void escape_through_call(int tag) {
395   zx_handle_t sa, sb;
396   if (zx_channel_create(0, &sa, &sb))
397     return;
398   escape1(&sa);
399   if (tag)
400     escape2(sb);
401   else
402     escape3(sb);
403 }
404 
405 struct have_handle {
406   zx_handle_t h;
407   zx_handle_t *hp;
408 };
409 
410 void escape_through_store01(have_handle *handle) {
411   zx_handle_t sa;
412   if (zx_channel_create(0, &sa, handle->hp))
413     return;
414   handle->h = sa;
415 }
416 
417 have_handle global;
418 void escape_through_store02() {
419   zx_handle_t sa;
420   if (zx_channel_create(0, &sa, global.hp))
421     return;
422   global.h = sa;
423 }
424 
425 have_handle escape_through_store03() {
426   zx_handle_t sa, sb;
427   if (zx_channel_create(0, &sa, &sb))
428     return {0, nullptr};
429   zx_handle_close(sb);
430   return {sa, nullptr};
431 }
432 
433 void escape_structs(have_handle *);
434 void escape_transitively01() {
435   zx_handle_t sa, sb;
436   if (zx_channel_create(0, &sa, &sb))
437     return;
438   have_handle hs[2];
439   hs[1] = {sa, &sb};
440   escape_structs(hs);
441 }
442 
443 void escape_top_level_pointees(zx_handle_t *h) {
444   zx_handle_t h2;
445   if (zx_channel_create(0, h, &h2))
446     return;
447   zx_handle_close(h2);
448 } // *h should be escaped here. Right?
449