509 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,fuchsia.HandleChecker -analyzer-output=text \2// RUN: -verify %s3 4typedef __typeof__(sizeof(int)) size_t;5typedef int zx_status_t;6typedef __typeof__(sizeof(int)) zx_handle_t;7typedef unsigned int uint32_t;8#define NULL ((void *)0)9#define ZX_HANDLE_INVALID 010 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#else17#define ZX_HANDLE_ACQUIRE18#define ZX_HANDLE_RELEASE19#define ZX_HANDLE_USE20#define ZX_HANDLE_ACQUIRE_UNOWNED21#endif22 23zx_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 28zx_status_t zx_handle_close(29 zx_handle_t handle ZX_HANDLE_RELEASE);30 31ZX_HANDLE_ACQUIRE_UNOWNED32zx_handle_t zx_process_self();33 34void zx_process_self_param(zx_handle_t *out ZX_HANDLE_ACQUIRE_UNOWNED);35 36ZX_HANDLE_ACQUIRE37zx_handle_t return_handle();38 39void escape1(zx_handle_t *in);40void escape2(zx_handle_t in);41void (*escape3)(zx_handle_t) = escape2;42 43void use1(const zx_handle_t *in ZX_HANDLE_USE);44void use2(zx_handle_t in ZX_HANDLE_USE);45 46void moreArgs(zx_handle_t, int, ...);47void lessArgs(zx_handle_t, int a = 5);48 49// To test if argument indexes are OK for operator calls.50struct MyType {51 ZX_HANDLE_ACQUIRE52 zx_handle_t operator+(zx_handle_t ZX_HANDLE_RELEASE replace);53};54 55void 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 62void 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 69void 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 81void 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 90void 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 98void 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 choosing102 // 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 112void 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 121void 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 128void 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 135void 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 142zx_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 warning147}148 149zx_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 warning154}155 156void 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 164void 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 178void 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 184void 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 213void 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 225void 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 244void 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 253struct HandleStruct {254 zx_handle_t h;255};256 257void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE);258 259void use_handle_struct(HandleStruct hs ZX_HANDLE_USE);260 261void 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 274void 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 287void 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 296struct HandlePtrStruct {297 zx_handle_t *h;298};299 300void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE);301 302void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE);303 304void 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 317void 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 330void 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 one340// header file while its implementation is in another file. We have to annotate341// 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.343zx_status_t test_release_handle(zx_handle_t handle ZX_HANDLE_RELEASE) {344 return zx_handle_close(handle);345}346 347void 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 354void use_handle(zx_handle_t handle) {355 // Do nothing.356}357 358void 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 366void 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 be371 // 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 be373 // reported leaked.374 use_handle(b);375} // expected-warning {{Potential leak of handle}}376// expected-note@-1 {{Potential leak of handle}}377 378// RAII379 380template <typename T>381struct HandleWrapper {382 ~HandleWrapper() { close(); }383 void close() {384 if (handle != ZX_HANDLE_INVALID)385 zx_handle_close(handle);386 }387 T *get_handle_address() { return &handle; }388 389private:390 T handle;391};392 393void 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 401template <typename T>402struct HandleWrapperUnkonwDtor {403 ~HandleWrapperUnkonwDtor();404 void close() {405 if (handle != ZX_HANDLE_INVALID)406 zx_handle_close(handle);407 }408 T *get_handle_address() { return &handle; }409 410private:411 T handle;412};413 414void 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 scenarios423 424zx_handle_t *get_handle_address();425 426void 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 433struct object {434 zx_handle_t *get_handle_address();435};436 437void 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 445void 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 454void 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 else462 escape3(sb);463}464 465struct have_handle {466 zx_handle_t h;467 zx_handle_t *hp;468};469 470void 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 477have_handle global;478void 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 485have_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 493void escape_structs(have_handle *);494void 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 503void 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