[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / test / Analysis / fuchsia_handle.cpp
blobf86cc50df045dafb32f1cb5d855ed79efa182d61
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,fuchsia.HandleChecker -analyzer-output=text \
2 // RUN: -verify %s
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
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
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);
28 zx_status_t zx_handle_close(
29 zx_handle_t handle ZX_HANDLE_RELEASE);
31 ZX_HANDLE_ACQUIRE_UNOWNED
32 zx_handle_t zx_process_self();
34 void zx_process_self_param(zx_handle_t *out ZX_HANDLE_ACQUIRE_UNOWNED);
36 ZX_HANDLE_ACQUIRE
37 zx_handle_t return_handle();
39 void escape1(zx_handle_t *in);
40 void escape2(zx_handle_t in);
41 void (*escape3)(zx_handle_t) = escape2;
43 void use1(const zx_handle_t *in ZX_HANDLE_USE);
44 void use2(zx_handle_t in ZX_HANDLE_USE);
46 void moreArgs(zx_handle_t, int, ...);
47 void lessArgs(zx_handle_t, int a = 5);
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);
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}}
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}}
69 void checkInvalidHandle01() {
70 zx_handle_t sa, sb;
71 zx_channel_create(0, &sa, &sb);
72 if (sa == ZX_HANDLE_INVALID)
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);
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);
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();
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}}
109 __builtin_trap();
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);
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);
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]);
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]);
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
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
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);
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);
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}}
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}}
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);
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}}
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}}
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);
253 struct HandleStruct {
254 zx_handle_t h;
257 void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE);
259 void use_handle_struct(HandleStruct hs ZX_HANDLE_USE);
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);
270 use2(sb); // expected-warning {{Using a previously released handle}}
271 // expected-note@-1 {{Using a previously released handle}}
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);
283 use_handle_struct(hs); // expected-warning {{Using a previously released handle}}
284 // expected-note@-1 {{Using a previously released handle}}
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}}
296 struct HandlePtrStruct {
297 zx_handle_t *h;
300 void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE);
302 void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE);
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);
313 use2(sb); // expected-warning {{Using a previously released handle}}
314 // expected-note@-1 {{Using a previously released handle}}
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);
326 use_handle_struct(hs); // expected-warning {{Using a previously released handle}}
327 // expected-note@-1 {{Using a previously released handle}}
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}}
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.
343 zx_status_t test_release_handle(zx_handle_t handle ZX_HANDLE_RELEASE) {
344 return zx_handle_close(handle);
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);
354 void use_handle(zx_handle_t handle) {
355 // Do nothing.
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);
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}}
378 // RAII
380 template <typename T>
381 struct HandleWrapper {
382 ~HandleWrapper() { close(); }
383 void close() {
384 if (handle != ZX_HANDLE_INVALID)
385 zx_handle_close(handle);
387 T *get_handle_address() { return &handle; }
389 private:
390 T handle;
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);
401 template <typename T>
402 struct HandleWrapperUnkonwDtor {
403 ~HandleWrapperUnkonwDtor();
404 void close() {
405 if (handle != ZX_HANDLE_INVALID)
406 zx_handle_close(handle);
408 T *get_handle_address() { return &handle; }
410 private:
411 T handle;
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);
422 // Various escaping scenarios
424 zx_handle_t *get_handle_address();
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);
433 struct object {
434 zx_handle_t *get_handle_address();
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);
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);
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);
465 struct have_handle {
466 zx_handle_t h;
467 zx_handle_t *hp;
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;
477 have_handle global;
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;
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};
493 void escape_structs(have_handle *);
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);
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?