xref: /llvm-project/clang/test/Analysis/fuchsia_handle.cpp (revision 8deaec122ec68746c53ec2afb893873124053d8d)
159878ec8SGabor Horvath // RUN: %clang_analyze_cc1 -analyzer-checker=core,fuchsia.HandleChecker -analyzer-output=text \
259878ec8SGabor Horvath // RUN:     -verify %s
382923c71SGabor Horvath 
482923c71SGabor Horvath typedef __typeof__(sizeof(int)) size_t;
582923c71SGabor Horvath typedef int zx_status_t;
682923c71SGabor Horvath typedef __typeof__(sizeof(int)) zx_handle_t;
782923c71SGabor Horvath typedef unsigned int uint32_t;
882923c71SGabor Horvath #define NULL ((void *)0)
982923c71SGabor Horvath #define ZX_HANDLE_INVALID 0
1082923c71SGabor Horvath 
1182923c71SGabor Horvath #if defined(__clang__)
1282923c71SGabor Horvath #define ZX_HANDLE_ACQUIRE __attribute__((acquire_handle("Fuchsia")))
1382923c71SGabor Horvath #define ZX_HANDLE_RELEASE __attribute__((release_handle("Fuchsia")))
1482923c71SGabor Horvath #define ZX_HANDLE_USE __attribute__((use_handle("Fuchsia")))
15*8deaec12SDaniel Hwang #define ZX_HANDLE_ACQUIRE_UNOWNED __attribute__((acquire_handle("FuchsiaUnowned")))
1682923c71SGabor Horvath #else
1782923c71SGabor Horvath #define ZX_HANDLE_ACQUIRE
1882923c71SGabor Horvath #define ZX_HANDLE_RELEASE
1982923c71SGabor Horvath #define ZX_HANDLE_USE
20*8deaec12SDaniel Hwang #define ZX_HANDLE_ACQUIRE_UNOWNED
2182923c71SGabor Horvath #endif
2282923c71SGabor Horvath 
2382923c71SGabor Horvath zx_status_t zx_channel_create(
2482923c71SGabor Horvath     uint32_t options,
2582923c71SGabor Horvath     zx_handle_t *out0 ZX_HANDLE_ACQUIRE,
2682923c71SGabor Horvath     zx_handle_t *out1 ZX_HANDLE_ACQUIRE);
2782923c71SGabor Horvath 
2882923c71SGabor Horvath zx_status_t zx_handle_close(
2982923c71SGabor Horvath     zx_handle_t handle ZX_HANDLE_RELEASE);
3082923c71SGabor Horvath 
31*8deaec12SDaniel Hwang ZX_HANDLE_ACQUIRE_UNOWNED
32*8deaec12SDaniel Hwang zx_handle_t zx_process_self();
33*8deaec12SDaniel Hwang 
34*8deaec12SDaniel Hwang void zx_process_self_param(zx_handle_t *out ZX_HANDLE_ACQUIRE_UNOWNED);
35*8deaec12SDaniel Hwang 
365911268eSGabor Horvath ZX_HANDLE_ACQUIRE
375911268eSGabor Horvath zx_handle_t return_handle();
385911268eSGabor Horvath 
3982923c71SGabor Horvath void escape1(zx_handle_t *in);
4082923c71SGabor Horvath void escape2(zx_handle_t in);
4182923c71SGabor Horvath void (*escape3)(zx_handle_t) = escape2;
4282923c71SGabor Horvath 
4382923c71SGabor Horvath void use1(const zx_handle_t *in ZX_HANDLE_USE);
4482923c71SGabor Horvath void use2(zx_handle_t in ZX_HANDLE_USE);
4582923c71SGabor Horvath 
4682923c71SGabor Horvath void moreArgs(zx_handle_t, int, ...);
4782923c71SGabor Horvath void lessArgs(zx_handle_t, int a = 5);
4882923c71SGabor Horvath 
4982923c71SGabor Horvath // To test if argument indexes are OK for operator calls.
5082923c71SGabor Horvath struct MyType {
5182923c71SGabor Horvath   ZX_HANDLE_ACQUIRE
5282923c71SGabor Horvath   zx_handle_t operator+(zx_handle_t ZX_HANDLE_RELEASE replace);
5382923c71SGabor Horvath };
5482923c71SGabor Horvath 
checkUnownedHandle01()55*8deaec12SDaniel Hwang void checkUnownedHandle01() {
56*8deaec12SDaniel Hwang   zx_handle_t h0;
57*8deaec12SDaniel Hwang   h0 = zx_process_self(); // expected-note {{Function 'zx_process_self' returns an unowned handle}}
58*8deaec12SDaniel Hwang   zx_handle_close(h0);    // expected-warning {{Releasing an unowned handle}}
59*8deaec12SDaniel Hwang                           // expected-note@-1 {{Releasing an unowned handle}}
60*8deaec12SDaniel Hwang }
61*8deaec12SDaniel Hwang 
checkUnownedHandle02()62*8deaec12SDaniel Hwang void checkUnownedHandle02() {
63*8deaec12SDaniel Hwang   zx_handle_t h0;
64*8deaec12SDaniel Hwang   zx_process_self_param(&h0); // expected-note {{Unowned handle allocated through 1st parameter}}
65*8deaec12SDaniel Hwang   zx_handle_close(h0);        // expected-warning {{Releasing an unowned handle}}
66*8deaec12SDaniel Hwang                               // expected-note@-1 {{Releasing an unowned handle}}
67*8deaec12SDaniel Hwang }
68*8deaec12SDaniel Hwang 
checkInvalidHandle01()6982923c71SGabor Horvath void checkInvalidHandle01() {
7082923c71SGabor Horvath   zx_handle_t sa, sb;
7182923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
7282923c71SGabor Horvath   if (sa == ZX_HANDLE_INVALID)
7382923c71SGabor Horvath     ;
7482923c71SGabor Horvath   // Will we ever see a warning like below?
7582923c71SGabor Horvath   // We eagerly replace the symbol with a constant and lose info...
7682923c71SGabor Horvath   use2(sa); // TODOexpected-warning {{Use of an invalid handle}}
7782923c71SGabor Horvath   zx_handle_close(sb);
7882923c71SGabor Horvath   zx_handle_close(sa);
7982923c71SGabor Horvath }
8082923c71SGabor Horvath 
checkInvalidHandle2()8182923c71SGabor Horvath void checkInvalidHandle2() {
8282923c71SGabor Horvath   zx_handle_t sa, sb;
8382923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
8482923c71SGabor Horvath   if (sb != ZX_HANDLE_INVALID)
8582923c71SGabor Horvath     zx_handle_close(sb);
8682923c71SGabor Horvath   if (sa != ZX_HANDLE_INVALID)
8782923c71SGabor Horvath     zx_handle_close(sa);
8882923c71SGabor Horvath }
8982923c71SGabor Horvath 
handleDieBeforeErrorSymbol01()90c98d98baSGabor Horvath void handleDieBeforeErrorSymbol01() {
91c98d98baSGabor Horvath   zx_handle_t sa, sb;
92c98d98baSGabor Horvath   zx_status_t status = zx_channel_create(0, &sa, &sb);
93c98d98baSGabor Horvath   if (status < 0)
94c98d98baSGabor Horvath     return;
95c98d98baSGabor Horvath   __builtin_trap();
96c98d98baSGabor Horvath }
97c98d98baSGabor Horvath 
handleDieBeforeErrorSymbol02()98c98d98baSGabor Horvath void handleDieBeforeErrorSymbol02() {
99c98d98baSGabor Horvath   zx_handle_t sa, sb;
100c98d98baSGabor Horvath   zx_status_t status = zx_channel_create(0, &sa, &sb);
101c26f237cSArtem Dergachev   // FIXME: There appears to be non-determinism in choosing
102c26f237cSArtem Dergachev   // which handle to report.
103c26f237cSArtem Dergachev   // expected-note-re@-3 {{Handle allocated through {{(2nd|3rd)}} parameter}}
104c98d98baSGabor Horvath   if (status == 0) { // expected-note {{Assuming 'status' is equal to 0}}
105c98d98baSGabor Horvath                      // expected-note@-1 {{Taking true branch}}
106c98d98baSGabor Horvath     return;          // expected-warning {{Potential leak of handle}}
107c98d98baSGabor Horvath                      // expected-note@-1 {{Potential leak of handle}}
108c98d98baSGabor Horvath   }
109c98d98baSGabor Horvath   __builtin_trap();
110c98d98baSGabor Horvath }
111c98d98baSGabor Horvath 
checkNoCrash01()11282923c71SGabor Horvath void checkNoCrash01() {
11382923c71SGabor Horvath   zx_handle_t sa, sb;
11482923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
11582923c71SGabor Horvath   moreArgs(sa, 1, 2, 3, 4, 5);
11682923c71SGabor Horvath   lessArgs(sa);
11782923c71SGabor Horvath   zx_handle_close(sa);
11882923c71SGabor Horvath   zx_handle_close(sb);
11982923c71SGabor Horvath }
12082923c71SGabor Horvath 
checkNoLeak01()12182923c71SGabor Horvath void checkNoLeak01() {
12282923c71SGabor Horvath   zx_handle_t sa, sb;
12382923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
12482923c71SGabor Horvath   zx_handle_close(sa);
12582923c71SGabor Horvath   zx_handle_close(sb);
12682923c71SGabor Horvath }
12782923c71SGabor Horvath 
checkNoLeak02()12882923c71SGabor Horvath void checkNoLeak02() {
12982923c71SGabor Horvath   zx_handle_t ay[2];
13082923c71SGabor Horvath   zx_channel_create(0, &ay[0], &ay[1]);
13182923c71SGabor Horvath   zx_handle_close(ay[0]);
13282923c71SGabor Horvath   zx_handle_close(ay[1]);
13382923c71SGabor Horvath }
13482923c71SGabor Horvath 
checkNoLeak03()13582923c71SGabor Horvath void checkNoLeak03() {
13682923c71SGabor Horvath   zx_handle_t ay[2];
13782923c71SGabor Horvath   zx_channel_create(0, &ay[0], &ay[1]);
13882923c71SGabor Horvath   for (int i = 0; i < 2; i++)
13982923c71SGabor Horvath     zx_handle_close(ay[i]);
14082923c71SGabor Horvath }
14182923c71SGabor Horvath 
checkNoLeak04()14282923c71SGabor Horvath zx_handle_t checkNoLeak04() {
14382923c71SGabor Horvath   zx_handle_t sa, sb;
14482923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
14582923c71SGabor Horvath   zx_handle_close(sa);
14682923c71SGabor Horvath   return sb; // no warning
14782923c71SGabor Horvath }
14882923c71SGabor Horvath 
checkNoLeak05(zx_handle_t * out1)14982923c71SGabor Horvath zx_handle_t checkNoLeak05(zx_handle_t *out1) {
15082923c71SGabor Horvath   zx_handle_t sa, sb;
15182923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
15282923c71SGabor Horvath   *out1 = sa;
15382923c71SGabor Horvath   return sb; // no warning
15482923c71SGabor Horvath }
15582923c71SGabor Horvath 
checkNoLeak06()15682923c71SGabor Horvath void checkNoLeak06() {
15782923c71SGabor Horvath   zx_handle_t sa, sb;
15882923c71SGabor Horvath   if (zx_channel_create(0, &sa, &sb))
15982923c71SGabor Horvath     return;
16082923c71SGabor Horvath   zx_handle_close(sa);
16182923c71SGabor Horvath   zx_handle_close(sb);
16282923c71SGabor Horvath }
16382923c71SGabor Horvath 
checkLeak01(int tag)16482923c71SGabor Horvath void checkLeak01(int tag) {
16582923c71SGabor Horvath   zx_handle_t sa, sb;
1665911268eSGabor Horvath   if (zx_channel_create(0, &sa, &sb)) // expected-note    {{Handle allocated through 2nd parameter}}
16759878ec8SGabor Horvath     return;                           // expected-note@-1 {{Assuming the condition is false}}
16859878ec8SGabor Horvath                                       // expected-note@-2 {{Taking false branch}}
16982923c71SGabor Horvath   use1(&sa);
17059878ec8SGabor Horvath   if (tag) // expected-note {{Assuming 'tag' is 0}}
17182923c71SGabor Horvath     zx_handle_close(sa);
17259878ec8SGabor Horvath   // expected-note@-2 {{Taking false branch}}
17382923c71SGabor Horvath   use2(sb); // expected-warning {{Potential leak of handle}}
17459878ec8SGabor Horvath   // expected-note@-1 {{Potential leak of handle}}
17582923c71SGabor Horvath   zx_handle_close(sb);
17682923c71SGabor Horvath }
17782923c71SGabor Horvath 
checkLeakFromReturn01(int tag)1785911268eSGabor Horvath void checkLeakFromReturn01(int tag) {
1795911268eSGabor Horvath   zx_handle_t sa = return_handle(); // expected-note {{Function 'return_handle' returns an open handle}}
1805911268eSGabor Horvath   (void)sa;
1815911268eSGabor Horvath } // expected-note {{Potential leak of handle}}
1825911268eSGabor Horvath // expected-warning@-1 {{Potential leak of handle}}
1835911268eSGabor Horvath 
checkReportLeakOnOnePath(int tag)18459878ec8SGabor Horvath void checkReportLeakOnOnePath(int tag) {
18559878ec8SGabor Horvath   zx_handle_t sa, sb;
1865911268eSGabor Horvath   if (zx_channel_create(0, &sa, &sb)) // expected-note {{Handle allocated through 2nd parameter}}
18759878ec8SGabor Horvath     return;                           // expected-note@-1 {{Assuming the condition is false}}
18859878ec8SGabor Horvath                                       // expected-note@-2 {{Taking false branch}}
18959878ec8SGabor Horvath   zx_handle_close(sb);
19059878ec8SGabor Horvath   switch (tag) { // expected-note {{Control jumps to the 'default' case at line}}
19159878ec8SGabor Horvath   case 0:
19259878ec8SGabor Horvath     use2(sa);
19359878ec8SGabor Horvath     return;
19459878ec8SGabor Horvath   case 1:
19559878ec8SGabor Horvath     use2(sa);
19659878ec8SGabor Horvath     return;
19759878ec8SGabor Horvath   case 2:
19859878ec8SGabor Horvath     use2(sa);
19959878ec8SGabor Horvath     return;
20059878ec8SGabor Horvath   case 3:
20159878ec8SGabor Horvath     use2(sa);
20259878ec8SGabor Horvath     return;
20359878ec8SGabor Horvath   case 4:
20459878ec8SGabor Horvath     use2(sa);
20559878ec8SGabor Horvath     return;
20659878ec8SGabor Horvath   default:
20759878ec8SGabor Horvath     use2(sa);
20859878ec8SGabor Horvath     return; // expected-warning {{Potential leak of handle}}
20959878ec8SGabor Horvath             // expected-note@-1 {{Potential leak of handle}}
21059878ec8SGabor Horvath   }
21159878ec8SGabor Horvath }
21259878ec8SGabor Horvath 
checkDoubleRelease01(int tag)21382923c71SGabor Horvath void checkDoubleRelease01(int tag) {
21482923c71SGabor Horvath   zx_handle_t sa, sb;
21582923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
2165911268eSGabor Horvath   // expected-note@-1 {{Handle allocated through 2nd parameter}}
21759878ec8SGabor Horvath   if (tag)               // expected-note {{Assuming 'tag' is not equal to 0}}
2185911268eSGabor Horvath     zx_handle_close(sa); // expected-note {{Handle released through 1st parameter}}
21959878ec8SGabor Horvath   // expected-note@-2 {{Taking true branch}}
22082923c71SGabor Horvath   zx_handle_close(sa); // expected-warning {{Releasing a previously released handle}}
22159878ec8SGabor Horvath   // expected-note@-1 {{Releasing a previously released handle}}
22282923c71SGabor Horvath   zx_handle_close(sb);
22382923c71SGabor Horvath }
22482923c71SGabor Horvath 
checkUseAfterFree01(int tag)22582923c71SGabor Horvath void checkUseAfterFree01(int tag) {
22682923c71SGabor Horvath   zx_handle_t sa, sb;
22782923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
2285911268eSGabor Horvath   // expected-note@-1 {{Handle allocated through 2nd parameter}}
2295911268eSGabor Horvath   // expected-note@-2 {{Handle allocated through 3rd parameter}}
23059878ec8SGabor Horvath   // expected-note@+2 {{Taking true branch}}
23159878ec8SGabor Horvath   // expected-note@+1 {{Taking false branch}}
23282923c71SGabor Horvath   if (tag) {
23359878ec8SGabor Horvath     // expected-note@-1 {{Assuming 'tag' is not equal to 0}}
2345911268eSGabor Horvath     zx_handle_close(sa); // expected-note {{Handle released through 1st parameter}}
23582923c71SGabor Horvath     use1(&sa);           // expected-warning {{Using a previously released handle}}
23659878ec8SGabor Horvath     // expected-note@-1 {{Using a previously released handle}}
23782923c71SGabor Horvath   }
23859878ec8SGabor Horvath   // expected-note@-6 {{Assuming 'tag' is 0}}
2395911268eSGabor Horvath   zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}}
24082923c71SGabor Horvath   use2(sb);            // expected-warning {{Using a previously released handle}}
24159878ec8SGabor Horvath   // expected-note@-1 {{Using a previously released handle}}
24282923c71SGabor Horvath }
24382923c71SGabor Horvath 
checkMemberOperatorIndices()24482923c71SGabor Horvath void checkMemberOperatorIndices() {
24582923c71SGabor Horvath   zx_handle_t sa, sb, sc;
24682923c71SGabor Horvath   zx_channel_create(0, &sa, &sb);
24782923c71SGabor Horvath   zx_handle_close(sb);
24882923c71SGabor Horvath   MyType t;
24982923c71SGabor Horvath   sc = t + sa;
25082923c71SGabor Horvath   zx_handle_close(sc);
25182923c71SGabor Horvath }
25282923c71SGabor Horvath 
253914f6c4fSHaowei Wu struct HandleStruct {
254914f6c4fSHaowei Wu   zx_handle_t h;
255914f6c4fSHaowei Wu };
256914f6c4fSHaowei Wu 
257914f6c4fSHaowei Wu void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE);
258914f6c4fSHaowei Wu 
259914f6c4fSHaowei Wu void use_handle_struct(HandleStruct hs ZX_HANDLE_USE);
260914f6c4fSHaowei Wu 
checkHandleInStructureUseAfterFree()261914f6c4fSHaowei Wu void checkHandleInStructureUseAfterFree() {
262914f6c4fSHaowei Wu   zx_handle_t sa, sb;
263914f6c4fSHaowei Wu   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
264914f6c4fSHaowei Wu   HandleStruct hs;
265914f6c4fSHaowei Wu   hs.h = sb;
266914f6c4fSHaowei Wu   use_handle_struct(hs);
267914f6c4fSHaowei Wu   close_handle_struct(hs); // expected-note {{Handle released through 1st parameter}}
268914f6c4fSHaowei Wu   zx_handle_close(sa);
269914f6c4fSHaowei Wu 
270914f6c4fSHaowei Wu   use2(sb); // expected-warning {{Using a previously released handle}}
271914f6c4fSHaowei Wu   // expected-note@-1 {{Using a previously released handle}}
272914f6c4fSHaowei Wu }
273914f6c4fSHaowei Wu 
checkHandleInStructureUseAfterFree2()274914f6c4fSHaowei Wu void checkHandleInStructureUseAfterFree2() {
275914f6c4fSHaowei Wu   zx_handle_t sa, sb;
276914f6c4fSHaowei Wu   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
277914f6c4fSHaowei Wu   HandleStruct hs;
278914f6c4fSHaowei Wu   hs.h = sb;
279914f6c4fSHaowei Wu   use_handle_struct(hs);
280914f6c4fSHaowei Wu   zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}}
281914f6c4fSHaowei Wu   zx_handle_close(sa);
282914f6c4fSHaowei Wu 
283914f6c4fSHaowei Wu   use_handle_struct(hs); // expected-warning {{Using a previously released handle}}
284914f6c4fSHaowei Wu   // expected-note@-1 {{Using a previously released handle}}
285914f6c4fSHaowei Wu }
286914f6c4fSHaowei Wu 
checkHandleInStructureLeak()287914f6c4fSHaowei Wu void checkHandleInStructureLeak() {
288914f6c4fSHaowei Wu   zx_handle_t sa, sb;
289914f6c4fSHaowei Wu   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
290914f6c4fSHaowei Wu   HandleStruct hs;
291914f6c4fSHaowei Wu   hs.h = sb;
292914f6c4fSHaowei Wu   zx_handle_close(sa); // expected-warning {{Potential leak of handle}}
293914f6c4fSHaowei Wu   // expected-note@-1 {{Potential leak of handle}}
294914f6c4fSHaowei Wu }
295914f6c4fSHaowei Wu 
296914f6c4fSHaowei Wu struct HandlePtrStruct {
297914f6c4fSHaowei Wu   zx_handle_t *h;
298914f6c4fSHaowei Wu };
299914f6c4fSHaowei Wu 
300914f6c4fSHaowei Wu void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE);
301914f6c4fSHaowei Wu 
302914f6c4fSHaowei Wu void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE);
303914f6c4fSHaowei Wu 
checkHandlePtrInStructureUseAfterFree()304914f6c4fSHaowei Wu void checkHandlePtrInStructureUseAfterFree() {
305914f6c4fSHaowei Wu   zx_handle_t sa, sb;
306914f6c4fSHaowei Wu   zx_channel_create(0, &sa, &sb);
307914f6c4fSHaowei Wu   HandlePtrStruct hs;
308914f6c4fSHaowei Wu   hs.h = &sb;
309914f6c4fSHaowei Wu   use_handle_struct(hs);
310914f6c4fSHaowei Wu   close_handle_struct(hs); // expected-note {{Handle released through 1st parameter}}
311914f6c4fSHaowei Wu   zx_handle_close(sa);
312914f6c4fSHaowei Wu 
313914f6c4fSHaowei Wu   use2(sb); // expected-warning {{Using a previously released handle}}
314914f6c4fSHaowei Wu   // expected-note@-1 {{Using a previously released handle}}
315914f6c4fSHaowei Wu }
316914f6c4fSHaowei Wu 
checkHandlePtrInStructureUseAfterFree2()317914f6c4fSHaowei Wu void checkHandlePtrInStructureUseAfterFree2() {
318914f6c4fSHaowei Wu   zx_handle_t sa, sb;
319914f6c4fSHaowei Wu   zx_channel_create(0, &sa, &sb);
320914f6c4fSHaowei Wu   HandlePtrStruct hs;
321914f6c4fSHaowei Wu   hs.h = &sb;
322914f6c4fSHaowei Wu   use_handle_struct(hs);
323914f6c4fSHaowei Wu   zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}}
324914f6c4fSHaowei Wu   zx_handle_close(sa);
325914f6c4fSHaowei Wu 
326914f6c4fSHaowei Wu   use_handle_struct(hs); // expected-warning {{Using a previously released handle}}
327914f6c4fSHaowei Wu   // expected-note@-1 {{Using a previously released handle}}
328914f6c4fSHaowei Wu }
329914f6c4fSHaowei Wu 
checkHandlePtrInStructureLeak()330914f6c4fSHaowei Wu void checkHandlePtrInStructureLeak() {
331914f6c4fSHaowei Wu   zx_handle_t sa, sb;
332914f6c4fSHaowei Wu   zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}}
333914f6c4fSHaowei Wu   HandlePtrStruct hs;
334914f6c4fSHaowei Wu   hs.h = &sb;
335914f6c4fSHaowei Wu   zx_handle_close(sa); // expected-warning {{Potential leak of handle}}
336914f6c4fSHaowei Wu   // expected-note@-1 {{Potential leak of handle}}
337914f6c4fSHaowei Wu }
338914f6c4fSHaowei Wu 
3393ce78f54SYu Shan // Assume this function's declaration that has the release annotation is in one
3403ce78f54SYu Shan // header file while its implementation is in another file. We have to annotate
3413ce78f54SYu Shan // the declaration because it might be used outside the TU.
3423ce78f54SYu Shan // 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)3433ce78f54SYu Shan zx_status_t test_release_handle(zx_handle_t handle ZX_HANDLE_RELEASE) {
3443ce78f54SYu Shan   return zx_handle_close(handle);
3453ce78f54SYu Shan }
3463ce78f54SYu Shan 
checkReleaseImplementedFunc()3473ce78f54SYu Shan void checkReleaseImplementedFunc() {
3483ce78f54SYu Shan   zx_handle_t a, b;
3493ce78f54SYu Shan   zx_channel_create(0, &a, &b);
3503ce78f54SYu Shan   zx_handle_close(a);
3513ce78f54SYu Shan   test_release_handle(b);
3523ce78f54SYu Shan }
3533ce78f54SYu Shan 
use_handle(zx_handle_t handle)3543ce78f54SYu Shan void use_handle(zx_handle_t handle) {
3553ce78f54SYu Shan   // Do nothing.
3563ce78f54SYu Shan }
3573ce78f54SYu Shan 
test_call_by_value()3583ce78f54SYu Shan void test_call_by_value() {
3593ce78f54SYu Shan   zx_handle_t a, b;
3603ce78f54SYu Shan   zx_channel_create(0, &a, &b);
3613ce78f54SYu Shan   zx_handle_close(a);
3623ce78f54SYu Shan   use_handle(b);
3633ce78f54SYu Shan   zx_handle_close(b);
3643ce78f54SYu Shan }
3653ce78f54SYu Shan 
test_call_by_value_leak()3663ce78f54SYu Shan void test_call_by_value_leak() {
3673ce78f54SYu Shan   zx_handle_t a, b;
3683ce78f54SYu Shan   zx_channel_create(0, &a, &b); // expected-note {{Handle allocated through 3rd parameter}}
3693ce78f54SYu Shan   zx_handle_close(a);
3703ce78f54SYu Shan   // Here we are passing handle b as integer value to a function that could be
3713ce78f54SYu Shan   // analyzed by the analyzer, thus the handle should not be considered escaped.
3723ce78f54SYu Shan   // After the function 'use_handle', handle b is still tracked and should be
3733ce78f54SYu Shan   // reported leaked.
3743ce78f54SYu Shan   use_handle(b);
3753ce78f54SYu Shan } // expected-warning {{Potential leak of handle}}
3763ce78f54SYu Shan // expected-note@-1 {{Potential leak of handle}}
3773ce78f54SYu Shan 
37882923c71SGabor Horvath // RAII
37982923c71SGabor Horvath 
38082923c71SGabor Horvath template <typename T>
38182923c71SGabor Horvath struct HandleWrapper {
~HandleWrapperHandleWrapper38282923c71SGabor Horvath   ~HandleWrapper() { close(); }
closeHandleWrapper38382923c71SGabor Horvath   void close() {
38482923c71SGabor Horvath     if (handle != ZX_HANDLE_INVALID)
38582923c71SGabor Horvath       zx_handle_close(handle);
38682923c71SGabor Horvath   }
get_handle_addressHandleWrapper38782923c71SGabor Horvath   T *get_handle_address() { return &handle; }
388914f6c4fSHaowei Wu 
38982923c71SGabor Horvath private:
39082923c71SGabor Horvath   T handle;
39182923c71SGabor Horvath };
39282923c71SGabor Horvath 
doNotWarnOnRAII()39382923c71SGabor Horvath void doNotWarnOnRAII() {
39482923c71SGabor Horvath   HandleWrapper<zx_handle_t> w1;
39582923c71SGabor Horvath   zx_handle_t sb;
39682923c71SGabor Horvath   if (zx_channel_create(0, w1.get_handle_address(), &sb))
39782923c71SGabor Horvath     return;
39882923c71SGabor Horvath   zx_handle_close(sb);
39982923c71SGabor Horvath }
40082923c71SGabor Horvath 
40182923c71SGabor Horvath template <typename T>
40282923c71SGabor Horvath struct HandleWrapperUnkonwDtor {
40382923c71SGabor Horvath   ~HandleWrapperUnkonwDtor();
closeHandleWrapperUnkonwDtor40482923c71SGabor Horvath   void close() {
40582923c71SGabor Horvath     if (handle != ZX_HANDLE_INVALID)
40682923c71SGabor Horvath       zx_handle_close(handle);
40782923c71SGabor Horvath   }
get_handle_addressHandleWrapperUnkonwDtor40882923c71SGabor Horvath   T *get_handle_address() { return &handle; }
409914f6c4fSHaowei Wu 
41082923c71SGabor Horvath private:
41182923c71SGabor Horvath   T handle;
41282923c71SGabor Horvath };
41382923c71SGabor Horvath 
doNotWarnOnUnknownDtor()414d4cf4c66SAaron Ballman void doNotWarnOnUnknownDtor() {
41582923c71SGabor Horvath   HandleWrapperUnkonwDtor<zx_handle_t> w1;
41682923c71SGabor Horvath   zx_handle_t sb;
41782923c71SGabor Horvath   if (zx_channel_create(0, w1.get_handle_address(), &sb))
41882923c71SGabor Horvath     return;
41982923c71SGabor Horvath   zx_handle_close(sb);
42082923c71SGabor Horvath }
42182923c71SGabor Horvath 
42282923c71SGabor Horvath // Various escaping scenarios
42382923c71SGabor Horvath 
42482923c71SGabor Horvath zx_handle_t *get_handle_address();
42582923c71SGabor Horvath 
escape_store_to_escaped_region01()42682923c71SGabor Horvath void escape_store_to_escaped_region01() {
42782923c71SGabor Horvath   zx_handle_t sb;
42882923c71SGabor Horvath   if (zx_channel_create(0, get_handle_address(), &sb))
42982923c71SGabor Horvath     return;
43082923c71SGabor Horvath   zx_handle_close(sb);
43182923c71SGabor Horvath }
43282923c71SGabor Horvath 
43382923c71SGabor Horvath struct object {
43482923c71SGabor Horvath   zx_handle_t *get_handle_address();
43582923c71SGabor Horvath };
43682923c71SGabor Horvath 
escape_store_to_escaped_region02(object & o)43782923c71SGabor Horvath void escape_store_to_escaped_region02(object &o) {
43882923c71SGabor Horvath   zx_handle_t sb;
43982923c71SGabor Horvath   // Same as above.
44082923c71SGabor Horvath   if (zx_channel_create(0, o.get_handle_address(), &sb))
44182923c71SGabor Horvath     return;
44282923c71SGabor Horvath   zx_handle_close(sb);
44382923c71SGabor Horvath }
44482923c71SGabor Horvath 
escape_store_to_escaped_region03(object o)44582923c71SGabor Horvath void escape_store_to_escaped_region03(object o) {
44682923c71SGabor Horvath   zx_handle_t sb;
44782923c71SGabor Horvath   // Should we consider the pointee of get_handle_address escaped?
44882923c71SGabor Horvath   // Maybe we only should it consider escaped if o escapes?
44982923c71SGabor Horvath   if (zx_channel_create(0, o.get_handle_address(), &sb))
45082923c71SGabor Horvath     return;
45182923c71SGabor Horvath   zx_handle_close(sb);
45282923c71SGabor Horvath }
45382923c71SGabor Horvath 
escape_through_call(int tag)45482923c71SGabor Horvath void escape_through_call(int tag) {
45582923c71SGabor Horvath   zx_handle_t sa, sb;
45682923c71SGabor Horvath   if (zx_channel_create(0, &sa, &sb))
45782923c71SGabor Horvath     return;
45882923c71SGabor Horvath   escape1(&sa);
45982923c71SGabor Horvath   if (tag)
46082923c71SGabor Horvath     escape2(sb);
46182923c71SGabor Horvath   else
46282923c71SGabor Horvath     escape3(sb);
46382923c71SGabor Horvath }
46482923c71SGabor Horvath 
46582923c71SGabor Horvath struct have_handle {
46682923c71SGabor Horvath   zx_handle_t h;
46782923c71SGabor Horvath   zx_handle_t *hp;
46882923c71SGabor Horvath };
46982923c71SGabor Horvath 
escape_through_store01(have_handle * handle)47082923c71SGabor Horvath void escape_through_store01(have_handle *handle) {
47182923c71SGabor Horvath   zx_handle_t sa;
47282923c71SGabor Horvath   if (zx_channel_create(0, &sa, handle->hp))
47382923c71SGabor Horvath     return;
47482923c71SGabor Horvath   handle->h = sa;
47582923c71SGabor Horvath }
47682923c71SGabor Horvath 
47782923c71SGabor Horvath have_handle global;
escape_through_store02()47882923c71SGabor Horvath void escape_through_store02() {
47982923c71SGabor Horvath   zx_handle_t sa;
48082923c71SGabor Horvath   if (zx_channel_create(0, &sa, global.hp))
48182923c71SGabor Horvath     return;
48282923c71SGabor Horvath   global.h = sa;
48382923c71SGabor Horvath }
48482923c71SGabor Horvath 
escape_through_store03()48582923c71SGabor Horvath have_handle escape_through_store03() {
48682923c71SGabor Horvath   zx_handle_t sa, sb;
48782923c71SGabor Horvath   if (zx_channel_create(0, &sa, &sb))
48882923c71SGabor Horvath     return {0, nullptr};
48982923c71SGabor Horvath   zx_handle_close(sb);
49082923c71SGabor Horvath   return {sa, nullptr};
49182923c71SGabor Horvath }
49282923c71SGabor Horvath 
49382923c71SGabor Horvath void escape_structs(have_handle *);
escape_transitively01()49482923c71SGabor Horvath void escape_transitively01() {
49582923c71SGabor Horvath   zx_handle_t sa, sb;
49682923c71SGabor Horvath   if (zx_channel_create(0, &sa, &sb))
49782923c71SGabor Horvath     return;
49882923c71SGabor Horvath   have_handle hs[2];
49982923c71SGabor Horvath   hs[1] = {sa, &sb};
50082923c71SGabor Horvath   escape_structs(hs);
50182923c71SGabor Horvath }
50282923c71SGabor Horvath 
escape_top_level_pointees(zx_handle_t * h)50382923c71SGabor Horvath void escape_top_level_pointees(zx_handle_t *h) {
50482923c71SGabor Horvath   zx_handle_t h2;
50582923c71SGabor Horvath   if (zx_channel_create(0, h, &h2))
50682923c71SGabor Horvath     return;
50782923c71SGabor Horvath   zx_handle_close(h2);
50882923c71SGabor Horvath } // *h should be escaped here. Right?
509