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