1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,fuchsia.HandleChecker -analyzer-output=text \
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")))
17 #define ZX_HANDLE_ACQUIRE
18 #define ZX_HANDLE_RELEASE
20 #define ZX_HANDLE_ACQUIRE_UNOWNED
23 zx_status_t
zx_channel_create(
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
);
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.
52 zx_handle_t
operator+(zx_handle_t ZX_HANDLE_RELEASE replace
);
55 void checkUnownedHandle01() {
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() {
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() {
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}}
81 void checkInvalidHandle2() {
83 zx_channel_create(0, &sa
, &sb
);
84 if (sb
!= ZX_HANDLE_INVALID
)
86 if (sa
!= ZX_HANDLE_INVALID
)
90 void handleDieBeforeErrorSymbol01() {
92 zx_status_t status
= zx_channel_create(0, &sa
, &sb
);
98 void handleDieBeforeErrorSymbol02() {
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}}
112 void checkNoCrash01() {
114 zx_channel_create(0, &sa
, &sb
);
115 moreArgs(sa
, 1, 2, 3, 4, 5);
121 void checkNoLeak01() {
123 zx_channel_create(0, &sa
, &sb
);
128 void checkNoLeak02() {
130 zx_channel_create(0, &ay
[0], &ay
[1]);
131 zx_handle_close(ay
[0]);
132 zx_handle_close(ay
[1]);
135 void checkNoLeak03() {
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() {
144 zx_channel_create(0, &sa
, &sb
);
146 return sb
; // no warning
149 zx_handle_t
checkNoLeak05(zx_handle_t
*out1
) {
151 zx_channel_create(0, &sa
, &sb
);
153 return sb
; // no warning
156 void checkNoLeak06() {
158 if (zx_channel_create(0, &sa
, &sb
))
164 void checkLeak01(int tag
) {
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}}
170 if (tag
) // expected-note {{Assuming 'tag' is 0}}
172 // expected-note@-2 {{Taking false branch}}
173 use2(sb
); // expected-warning {{Potential leak of handle}}
174 // expected-note@-1 {{Potential leak of handle}}
178 void checkLeakFromReturn01(int tag
) {
179 zx_handle_t sa
= return_handle(); // expected-note {{Function 'return_handle' returns an open handle}}
181 } // expected-note {{Potential leak of handle}}
182 // expected-warning@-1 {{Potential leak of handle}}
184 void checkReportLeakOnOnePath(int tag
) {
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}}
190 switch (tag
) { // expected-note {{Control jumps to the 'default' case at line}}
208 return; // expected-warning {{Potential leak of handle}}
209 // expected-note@-1 {{Potential leak of handle}}
213 void checkDoubleRelease01(int tag
) {
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}}
225 void checkUseAfterFree01(int tag
) {
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}}
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
);
253 struct HandleStruct
{
257 void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE
);
259 void use_handle_struct(HandleStruct hs ZX_HANDLE_USE
);
261 void checkHandleInStructureUseAfterFree() {
263 zx_channel_create(0, &sa
, &sb
); // expected-note {{Handle allocated through 3rd parameter}}
266 use_handle_struct(hs
);
267 close_handle_struct(hs
); // expected-note {{Handle released through 1st parameter}}
270 use2(sb
); // expected-warning {{Using a previously released handle}}
271 // expected-note@-1 {{Using a previously released handle}}
274 void checkHandleInStructureUseAfterFree2() {
276 zx_channel_create(0, &sa
, &sb
); // expected-note {{Handle allocated through 3rd parameter}}
279 use_handle_struct(hs
);
280 zx_handle_close(sb
); // expected-note {{Handle released through 1st parameter}}
283 use_handle_struct(hs
); // expected-warning {{Using a previously released handle}}
284 // expected-note@-1 {{Using a previously released handle}}
287 void checkHandleInStructureLeak() {
289 zx_channel_create(0, &sa
, &sb
); // expected-note {{Handle allocated through 3rd parameter}}
292 zx_handle_close(sa
); // expected-warning {{Potential leak of handle}}
293 // expected-note@-1 {{Potential leak of handle}}
296 struct HandlePtrStruct
{
300 void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE
);
302 void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE
);
304 void checkHandlePtrInStructureUseAfterFree() {
306 zx_channel_create(0, &sa
, &sb
);
309 use_handle_struct(hs
);
310 close_handle_struct(hs
); // expected-note {{Handle released through 1st parameter}}
313 use2(sb
); // expected-warning {{Using a previously released handle}}
314 // expected-note@-1 {{Using a previously released handle}}
317 void checkHandlePtrInStructureUseAfterFree2() {
319 zx_channel_create(0, &sa
, &sb
);
322 use_handle_struct(hs
);
323 zx_handle_close(sb
); // expected-note {{Handle released through 1st parameter}}
326 use_handle_struct(hs
); // expected-warning {{Using a previously released handle}}
327 // expected-note@-1 {{Using a previously released handle}}
330 void checkHandlePtrInStructureLeak() {
332 zx_channel_create(0, &sa
, &sb
); // expected-note {{Handle allocated through 3rd parameter}}
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() {
349 zx_channel_create(0, &a
, &b
);
351 test_release_handle(b
);
354 void use_handle(zx_handle_t handle
) {
358 void test_call_by_value() {
360 zx_channel_create(0, &a
, &b
);
366 void test_call_by_value_leak() {
368 zx_channel_create(0, &a
, &b
); // expected-note {{Handle allocated through 3rd parameter}}
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
375 } // expected-warning {{Potential leak of handle}}
376 // expected-note@-1 {{Potential leak of handle}}
380 template <typename T
>
381 struct HandleWrapper
{
382 ~HandleWrapper() { close(); }
384 if (handle
!= ZX_HANDLE_INVALID
)
385 zx_handle_close(handle
);
387 T
*get_handle_address() { return &handle
; }
393 void doNotWarnOnRAII() {
394 HandleWrapper
<zx_handle_t
> w1
;
396 if (zx_channel_create(0, w1
.get_handle_address(), &sb
))
401 template <typename T
>
402 struct HandleWrapperUnkonwDtor
{
403 ~HandleWrapperUnkonwDtor();
405 if (handle
!= ZX_HANDLE_INVALID
)
406 zx_handle_close(handle
);
408 T
*get_handle_address() { return &handle
; }
414 void doNotWarnOnUnknownDtor() {
415 HandleWrapperUnkonwDtor
<zx_handle_t
> w1
;
417 if (zx_channel_create(0, w1
.get_handle_address(), &sb
))
422 // Various escaping scenarios
424 zx_handle_t
*get_handle_address();
426 void escape_store_to_escaped_region01() {
428 if (zx_channel_create(0, get_handle_address(), &sb
))
434 zx_handle_t
*get_handle_address();
437 void escape_store_to_escaped_region02(object
&o
) {
440 if (zx_channel_create(0, o
.get_handle_address(), &sb
))
445 void escape_store_to_escaped_region03(object o
) {
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
))
454 void escape_through_call(int tag
) {
456 if (zx_channel_create(0, &sa
, &sb
))
470 void escape_through_store01(have_handle
*handle
) {
472 if (zx_channel_create(0, &sa
, handle
->hp
))
478 void escape_through_store02() {
480 if (zx_channel_create(0, &sa
, global
.hp
))
485 have_handle
escape_through_store03() {
487 if (zx_channel_create(0, &sa
, &sb
))
490 return {sa
, nullptr};
493 void escape_structs(have_handle
*);
494 void escape_transitively01() {
496 if (zx_channel_create(0, &sa
, &sb
))
503 void escape_top_level_pointees(zx_handle_t
*h
) {
505 if (zx_channel_create(0, h
, &h2
))
508 } // *h should be escaped here. Right?