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 #else 16 #define ZX_HANDLE_ACQUIRE 17 #define ZX_HANDLE_RELEASE 18 #define ZX_HANDLE_USE 19 #endif 20 21 zx_status_t zx_channel_create( 22 uint32_t options, 23 zx_handle_t *out0 ZX_HANDLE_ACQUIRE, 24 zx_handle_t *out1 ZX_HANDLE_ACQUIRE); 25 26 zx_status_t zx_handle_close( 27 zx_handle_t handle ZX_HANDLE_RELEASE); 28 29 ZX_HANDLE_ACQUIRE 30 zx_handle_t return_handle(); 31 32 void escape1(zx_handle_t *in); 33 void escape2(zx_handle_t in); 34 void (*escape3)(zx_handle_t) = escape2; 35 36 void use1(const zx_handle_t *in ZX_HANDLE_USE); 37 void use2(zx_handle_t in ZX_HANDLE_USE); 38 39 void moreArgs(zx_handle_t, int, ...); 40 void lessArgs(zx_handle_t, int a = 5); 41 42 // To test if argument indexes are OK for operator calls. 43 struct MyType { 44 ZX_HANDLE_ACQUIRE 45 zx_handle_t operator+(zx_handle_t ZX_HANDLE_RELEASE replace); 46 }; 47 48 void checkInvalidHandle01() { 49 zx_handle_t sa, sb; 50 zx_channel_create(0, &sa, &sb); 51 if (sa == ZX_HANDLE_INVALID) 52 ; 53 // Will we ever see a warning like below? 54 // We eagerly replace the symbol with a constant and lose info... 55 use2(sa); // TODOexpected-warning {{Use of an invalid handle}} 56 zx_handle_close(sb); 57 zx_handle_close(sa); 58 } 59 60 void checkInvalidHandle2() { 61 zx_handle_t sa, sb; 62 zx_channel_create(0, &sa, &sb); 63 if (sb != ZX_HANDLE_INVALID) 64 zx_handle_close(sb); 65 if (sa != ZX_HANDLE_INVALID) 66 zx_handle_close(sa); 67 } 68 69 void handleDieBeforeErrorSymbol01() { 70 zx_handle_t sa, sb; 71 zx_status_t status = zx_channel_create(0, &sa, &sb); 72 if (status < 0) 73 return; 74 __builtin_trap(); 75 } 76 77 void handleDieBeforeErrorSymbol02() { 78 zx_handle_t sa, sb; 79 zx_status_t status = zx_channel_create(0, &sa, &sb); 80 // FIXME: There appears to be non-determinism in choosing 81 // which handle to report. 82 // expected-note-re@-3 {{Handle allocated through {{(2nd|3rd)}} parameter}} 83 if (status == 0) { // expected-note {{Assuming 'status' is equal to 0}} 84 // expected-note@-1 {{Taking true branch}} 85 return; // expected-warning {{Potential leak of handle}} 86 // expected-note@-1 {{Potential leak of handle}} 87 } 88 __builtin_trap(); 89 } 90 91 void checkNoCrash01() { 92 zx_handle_t sa, sb; 93 zx_channel_create(0, &sa, &sb); 94 moreArgs(sa, 1, 2, 3, 4, 5); 95 lessArgs(sa); 96 zx_handle_close(sa); 97 zx_handle_close(sb); 98 } 99 100 void checkNoLeak01() { 101 zx_handle_t sa, sb; 102 zx_channel_create(0, &sa, &sb); 103 zx_handle_close(sa); 104 zx_handle_close(sb); 105 } 106 107 void checkNoLeak02() { 108 zx_handle_t ay[2]; 109 zx_channel_create(0, &ay[0], &ay[1]); 110 zx_handle_close(ay[0]); 111 zx_handle_close(ay[1]); 112 } 113 114 void checkNoLeak03() { 115 zx_handle_t ay[2]; 116 zx_channel_create(0, &ay[0], &ay[1]); 117 for (int i = 0; i < 2; i++) 118 zx_handle_close(ay[i]); 119 } 120 121 zx_handle_t checkNoLeak04() { 122 zx_handle_t sa, sb; 123 zx_channel_create(0, &sa, &sb); 124 zx_handle_close(sa); 125 return sb; // no warning 126 } 127 128 zx_handle_t checkNoLeak05(zx_handle_t *out1) { 129 zx_handle_t sa, sb; 130 zx_channel_create(0, &sa, &sb); 131 *out1 = sa; 132 return sb; // no warning 133 } 134 135 void checkNoLeak06() { 136 zx_handle_t sa, sb; 137 if (zx_channel_create(0, &sa, &sb)) 138 return; 139 zx_handle_close(sa); 140 zx_handle_close(sb); 141 } 142 143 void checkLeak01(int tag) { 144 zx_handle_t sa, sb; 145 if (zx_channel_create(0, &sa, &sb)) // expected-note {{Handle allocated through 2nd parameter}} 146 return; // expected-note@-1 {{Assuming the condition is false}} 147 // expected-note@-2 {{Taking false branch}} 148 use1(&sa); 149 if (tag) // expected-note {{Assuming 'tag' is 0}} 150 zx_handle_close(sa); 151 // expected-note@-2 {{Taking false branch}} 152 use2(sb); // expected-warning {{Potential leak of handle}} 153 // expected-note@-1 {{Potential leak of handle}} 154 zx_handle_close(sb); 155 } 156 157 void checkLeakFromReturn01(int tag) { 158 zx_handle_t sa = return_handle(); // expected-note {{Function 'return_handle' returns an open handle}} 159 (void)sa; 160 } // expected-note {{Potential leak of handle}} 161 // expected-warning@-1 {{Potential leak of handle}} 162 163 void checkReportLeakOnOnePath(int tag) { 164 zx_handle_t sa, sb; 165 if (zx_channel_create(0, &sa, &sb)) // expected-note {{Handle allocated through 2nd parameter}} 166 return; // expected-note@-1 {{Assuming the condition is false}} 167 // expected-note@-2 {{Taking false branch}} 168 zx_handle_close(sb); 169 switch (tag) { // expected-note {{Control jumps to the 'default' case at line}} 170 case 0: 171 use2(sa); 172 return; 173 case 1: 174 use2(sa); 175 return; 176 case 2: 177 use2(sa); 178 return; 179 case 3: 180 use2(sa); 181 return; 182 case 4: 183 use2(sa); 184 return; 185 default: 186 use2(sa); 187 return; // expected-warning {{Potential leak of handle}} 188 // expected-note@-1 {{Potential leak of handle}} 189 } 190 } 191 192 void checkDoubleRelease01(int tag) { 193 zx_handle_t sa, sb; 194 zx_channel_create(0, &sa, &sb); 195 // expected-note@-1 {{Handle allocated through 2nd parameter}} 196 if (tag) // expected-note {{Assuming 'tag' is not equal to 0}} 197 zx_handle_close(sa); // expected-note {{Handle released through 1st parameter}} 198 // expected-note@-2 {{Taking true branch}} 199 zx_handle_close(sa); // expected-warning {{Releasing a previously released handle}} 200 // expected-note@-1 {{Releasing a previously released handle}} 201 zx_handle_close(sb); 202 } 203 204 void checkUseAfterFree01(int tag) { 205 zx_handle_t sa, sb; 206 zx_channel_create(0, &sa, &sb); 207 // expected-note@-1 {{Handle allocated through 2nd parameter}} 208 // expected-note@-2 {{Handle allocated through 3rd parameter}} 209 // expected-note@+2 {{Taking true branch}} 210 // expected-note@+1 {{Taking false branch}} 211 if (tag) { 212 // expected-note@-1 {{Assuming 'tag' is not equal to 0}} 213 zx_handle_close(sa); // expected-note {{Handle released through 1st parameter}} 214 use1(&sa); // expected-warning {{Using a previously released handle}} 215 // expected-note@-1 {{Using a previously released handle}} 216 } 217 // expected-note@-6 {{Assuming 'tag' is 0}} 218 zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}} 219 use2(sb); // expected-warning {{Using a previously released handle}} 220 // expected-note@-1 {{Using a previously released handle}} 221 } 222 223 void checkMemberOperatorIndices() { 224 zx_handle_t sa, sb, sc; 225 zx_channel_create(0, &sa, &sb); 226 zx_handle_close(sb); 227 MyType t; 228 sc = t + sa; 229 zx_handle_close(sc); 230 } 231 232 struct HandleStruct { 233 zx_handle_t h; 234 }; 235 236 void close_handle_struct(HandleStruct hs ZX_HANDLE_RELEASE); 237 238 void use_handle_struct(HandleStruct hs ZX_HANDLE_USE); 239 240 void checkHandleInStructureUseAfterFree() { 241 zx_handle_t sa, sb; 242 zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}} 243 HandleStruct hs; 244 hs.h = sb; 245 use_handle_struct(hs); 246 close_handle_struct(hs); // expected-note {{Handle released through 1st parameter}} 247 zx_handle_close(sa); 248 249 use2(sb); // expected-warning {{Using a previously released handle}} 250 // expected-note@-1 {{Using a previously released handle}} 251 } 252 253 void checkHandleInStructureUseAfterFree2() { 254 zx_handle_t sa, sb; 255 zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}} 256 HandleStruct hs; 257 hs.h = sb; 258 use_handle_struct(hs); 259 zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}} 260 zx_handle_close(sa); 261 262 use_handle_struct(hs); // expected-warning {{Using a previously released handle}} 263 // expected-note@-1 {{Using a previously released handle}} 264 } 265 266 void checkHandleInStructureLeak() { 267 zx_handle_t sa, sb; 268 zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}} 269 HandleStruct hs; 270 hs.h = sb; 271 zx_handle_close(sa); // expected-warning {{Potential leak of handle}} 272 // expected-note@-1 {{Potential leak of handle}} 273 } 274 275 struct HandlePtrStruct { 276 zx_handle_t *h; 277 }; 278 279 void close_handle_struct(HandlePtrStruct hs ZX_HANDLE_RELEASE); 280 281 void use_handle_struct(HandlePtrStruct hs ZX_HANDLE_USE); 282 283 void checkHandlePtrInStructureUseAfterFree() { 284 zx_handle_t sa, sb; 285 zx_channel_create(0, &sa, &sb); 286 HandlePtrStruct hs; 287 hs.h = &sb; 288 use_handle_struct(hs); 289 close_handle_struct(hs); // expected-note {{Handle released through 1st parameter}} 290 zx_handle_close(sa); 291 292 use2(sb); // expected-warning {{Using a previously released handle}} 293 // expected-note@-1 {{Using a previously released handle}} 294 } 295 296 void checkHandlePtrInStructureUseAfterFree2() { 297 zx_handle_t sa, sb; 298 zx_channel_create(0, &sa, &sb); 299 HandlePtrStruct hs; 300 hs.h = &sb; 301 use_handle_struct(hs); 302 zx_handle_close(sb); // expected-note {{Handle released through 1st parameter}} 303 zx_handle_close(sa); 304 305 use_handle_struct(hs); // expected-warning {{Using a previously released handle}} 306 // expected-note@-1 {{Using a previously released handle}} 307 } 308 309 void checkHandlePtrInStructureLeak() { 310 zx_handle_t sa, sb; 311 zx_channel_create(0, &sa, &sb); // expected-note {{Handle allocated through 3rd parameter}} 312 HandlePtrStruct hs; 313 hs.h = &sb; 314 zx_handle_close(sa); // expected-warning {{Potential leak of handle}} 315 // expected-note@-1 {{Potential leak of handle}} 316 } 317 318 // RAII 319 320 template <typename T> 321 struct HandleWrapper { 322 ~HandleWrapper() { close(); } 323 void close() { 324 if (handle != ZX_HANDLE_INVALID) 325 zx_handle_close(handle); 326 } 327 T *get_handle_address() { return &handle; } 328 329 private: 330 T handle; 331 }; 332 333 void doNotWarnOnRAII() { 334 HandleWrapper<zx_handle_t> w1; 335 zx_handle_t sb; 336 if (zx_channel_create(0, w1.get_handle_address(), &sb)) 337 return; 338 zx_handle_close(sb); 339 } 340 341 template <typename T> 342 struct HandleWrapperUnkonwDtor { 343 ~HandleWrapperUnkonwDtor(); 344 void close() { 345 if (handle != ZX_HANDLE_INVALID) 346 zx_handle_close(handle); 347 } 348 T *get_handle_address() { return &handle; } 349 350 private: 351 T handle; 352 }; 353 354 void doNotWarnOnUnknownDtor() { 355 HandleWrapperUnkonwDtor<zx_handle_t> w1; 356 zx_handle_t sb; 357 if (zx_channel_create(0, w1.get_handle_address(), &sb)) 358 return; 359 zx_handle_close(sb); 360 } 361 362 // Various escaping scenarios 363 364 zx_handle_t *get_handle_address(); 365 366 void escape_store_to_escaped_region01() { 367 zx_handle_t sb; 368 if (zx_channel_create(0, get_handle_address(), &sb)) 369 return; 370 zx_handle_close(sb); 371 } 372 373 struct object { 374 zx_handle_t *get_handle_address(); 375 }; 376 377 void escape_store_to_escaped_region02(object &o) { 378 zx_handle_t sb; 379 // Same as above. 380 if (zx_channel_create(0, o.get_handle_address(), &sb)) 381 return; 382 zx_handle_close(sb); 383 } 384 385 void escape_store_to_escaped_region03(object o) { 386 zx_handle_t sb; 387 // Should we consider the pointee of get_handle_address escaped? 388 // Maybe we only should it consider escaped if o escapes? 389 if (zx_channel_create(0, o.get_handle_address(), &sb)) 390 return; 391 zx_handle_close(sb); 392 } 393 394 void escape_through_call(int tag) { 395 zx_handle_t sa, sb; 396 if (zx_channel_create(0, &sa, &sb)) 397 return; 398 escape1(&sa); 399 if (tag) 400 escape2(sb); 401 else 402 escape3(sb); 403 } 404 405 struct have_handle { 406 zx_handle_t h; 407 zx_handle_t *hp; 408 }; 409 410 void escape_through_store01(have_handle *handle) { 411 zx_handle_t sa; 412 if (zx_channel_create(0, &sa, handle->hp)) 413 return; 414 handle->h = sa; 415 } 416 417 have_handle global; 418 void escape_through_store02() { 419 zx_handle_t sa; 420 if (zx_channel_create(0, &sa, global.hp)) 421 return; 422 global.h = sa; 423 } 424 425 have_handle escape_through_store03() { 426 zx_handle_t sa, sb; 427 if (zx_channel_create(0, &sa, &sb)) 428 return {0, nullptr}; 429 zx_handle_close(sb); 430 return {sa, nullptr}; 431 } 432 433 void escape_structs(have_handle *); 434 void escape_transitively01() { 435 zx_handle_t sa, sb; 436 if (zx_channel_create(0, &sa, &sb)) 437 return; 438 have_handle hs[2]; 439 hs[1] = {sa, &sb}; 440 escape_structs(hs); 441 } 442 443 void escape_top_level_pointees(zx_handle_t *h) { 444 zx_handle_t h2; 445 if (zx_channel_create(0, h, &h2)) 446 return; 447 zx_handle_close(h2); 448 } // *h should be escaped here. Right? 449