1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,fuchsia.HandleChecker -analyzer-output=text \ 2 // RUN: -verify %s 3 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 10 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 22 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); 27 28 zx_status_t zx_handle_close( 29 zx_handle_t handle ZX_HANDLE_RELEASE); 30 31 ZX_HANDLE_ACQUIRE_UNOWNED 32 zx_handle_t zx_process_self(); 33 34 void zx_process_self_param(zx_handle_t *out ZX_HANDLE_ACQUIRE_UNOWNED); 35 36 ZX_HANDLE_ACQUIRE 37 zx_handle_t return_handle(); 38 39 void escape1(zx_handle_t *in); 40 void escape2(zx_handle_t in); 41 void (*escape3)(zx_handle_t) = escape2; 42 43 void use1(const zx_handle_t *in ZX_HANDLE_USE); 44 void use2(zx_handle_t in ZX_HANDLE_USE); 45 46 void moreArgs(zx_handle_t, int, ...); 47 void lessArgs(zx_handle_t, int a = 5); 48 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); 53 }; 54 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}} 60 } 61 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}} 67 } 68 69 void 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 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); 88 } 89 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(); 96 } 97 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}} 108 } 109 __builtin_trap(); 110 } 111 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); 119 } 120 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); 126 } 127 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]); 133 } 134 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]); 140 } 141 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 147 } 148 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 154 } 155 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); 162 } 163 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); 176 } 177 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}} 183 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}} 210 } 211 } 212 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); 223 } 224 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}} 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 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); 251 } 252 253 struct HandleStruct { 254 zx_handle_t h; 255 }; 256 257 void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE); 258 259 void use_handle_struct(HandleStruct hs ZX_HANDLE_USE); 260 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); 269 270 use2(sb); // expected-warning {{Using a previously released handle}} 271 // expected-note@-1 {{Using a previously released handle}} 272 } 273 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); 282 283 use_handle_struct(hs); // expected-warning {{Using a previously released handle}} 284 // expected-note@-1 {{Using a previously released handle}} 285 } 286 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}} 294 } 295 296 struct HandlePtrStruct { 297 zx_handle_t *h; 298 }; 299 300 void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE); 301 302 void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE); 303 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); 312 313 use2(sb); // expected-warning {{Using a previously released handle}} 314 // expected-note@-1 {{Using a previously released handle}} 315 } 316 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); 325 326 use_handle_struct(hs); // expected-warning {{Using a previously released handle}} 327 // expected-note@-1 {{Using a previously released handle}} 328 } 329 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}} 337 } 338 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); 345 } 346 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); 352 } 353 354 void use_handle(zx_handle_t handle) { 355 // Do nothing. 356 } 357 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); 364 } 365 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}} 377 378 // RAII 379 380 template <typename T> 381 struct 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 389 private: 390 T handle; 391 }; 392 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); 399 } 400 401 template <typename T> 402 struct 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 410 private: 411 T handle; 412 }; 413 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); 420 } 421 422 // Various escaping scenarios 423 424 zx_handle_t *get_handle_address(); 425 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); 431 } 432 433 struct object { 434 zx_handle_t *get_handle_address(); 435 }; 436 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); 443 } 444 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); 452 } 453 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); 463 } 464 465 struct have_handle { 466 zx_handle_t h; 467 zx_handle_t *hp; 468 }; 469 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; 475 } 476 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; 483 } 484 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}; 491 } 492 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); 501 } 502 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? 509