brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.1 KiB · f86cc50 Raw
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