1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedLocalVarsChecker -verify %s 2 3 #include "mock-types.h" 4 #include "mock-system-header.h" 5 6 void someFunction(); 7 8 namespace raw_ptr { 9 void foo() { 10 RefCountable *bar; 11 // FIXME: later on we might warn on uninitialized vars too 12 } 13 14 void bar(RefCountable *) {} 15 } // namespace raw_ptr 16 17 namespace reference { 18 void foo_ref() { 19 RefCountable automatic; 20 RefCountable &bar = automatic; 21 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 22 someFunction(); 23 bar.method(); 24 } 25 26 void foo_ref_trivial() { 27 RefCountable automatic; 28 RefCountable &bar = automatic; 29 } 30 31 void bar_ref(RefCountable &) {} 32 } // namespace reference 33 34 namespace guardian_scopes { 35 void foo1() { 36 RefPtr<RefCountable> foo; 37 { RefCountable *bar = foo.get(); } 38 } 39 40 void foo2() { 41 RefPtr<RefCountable> foo; 42 // missing embedded scope here 43 RefCountable *bar = foo.get(); 44 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 45 someFunction(); 46 bar->method(); 47 } 48 49 void foo3() { 50 RefPtr<RefCountable> foo; 51 { 52 { RefCountable *bar = foo.get(); } 53 } 54 } 55 56 void foo4() { 57 { 58 RefPtr<RefCountable> foo; 59 { RefCountable *bar = foo.get(); } 60 } 61 } 62 63 void foo5() { 64 RefPtr<RefCountable> foo; 65 auto* bar = foo.get(); 66 bar->trivial(); 67 } 68 69 void foo6() { 70 RefPtr<RefCountable> foo; 71 auto* bar = foo.get(); 72 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 73 bar->method(); 74 } 75 76 struct SelfReferencingStruct { 77 SelfReferencingStruct* ptr; 78 RefCountable* obj { nullptr }; 79 }; 80 81 void foo7(RefCountable* obj) { 82 SelfReferencingStruct bar = { &bar, obj }; 83 bar.obj->method(); 84 } 85 86 void foo8(RefCountable* obj) { 87 RefPtr<RefCountable> foo; 88 { 89 RefCountable *bar = foo.get(); 90 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 91 foo = nullptr; 92 bar->method(); 93 } 94 RefPtr<RefCountable> baz; 95 { 96 RefCountable *bar = baz.get(); 97 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 98 baz = obj; 99 bar->method(); 100 } 101 foo = nullptr; 102 { 103 RefCountable *bar = foo.get(); 104 // No warning. It's okay to mutate RefPtr in an outer scope. 105 bar->method(); 106 } 107 foo = obj; 108 { 109 RefCountable *bar = foo.get(); 110 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 111 foo.releaseNonNull(); 112 bar->method(); 113 } 114 { 115 RefCountable *bar = foo.get(); 116 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 117 foo = obj ? obj : nullptr; 118 bar->method(); 119 } 120 { 121 RefCountable *bar = foo->trivial() ? foo.get() : nullptr; 122 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 123 foo = nullptr; 124 bar->method(); 125 } 126 } 127 128 void foo9(RefCountable& o) { 129 Ref<RefCountable> guardian(o); 130 { 131 RefCountable &bar = guardian.get(); 132 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 133 guardian = o; // We don't detect that we're setting it to the same value. 134 bar.method(); 135 } 136 { 137 RefCountable *bar = guardian.ptr(); 138 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 139 Ref<RefCountable> other(*bar); // We don't detect other has the same value as guardian. 140 guardian.swap(other); 141 bar->method(); 142 } 143 { 144 RefCountable *bar = guardian.ptr(); 145 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 146 Ref<RefCountable> other(static_cast<Ref<RefCountable>&&>(guardian)); 147 bar->method(); 148 } 149 { 150 RefCountable *bar = guardian.ptr(); 151 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 152 guardian.leakRef(); 153 bar->method(); 154 } 155 { 156 RefCountable *bar = guardian.ptr(); 157 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 158 guardian = o.trivial() ? o : *bar; 159 bar->method(); 160 } 161 } 162 163 } // namespace guardian_scopes 164 165 namespace auto_keyword { 166 class Foo { 167 RefCountable *provide_ref_ctnbl(); 168 169 void evil_func() { 170 RefCountable *bar = provide_ref_ctnbl(); 171 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 172 auto *baz = provide_ref_ctnbl(); 173 // expected-warning@-1{{Local variable 'baz' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 174 auto *baz2 = this->provide_ref_ctnbl(); 175 // expected-warning@-1{{Local variable 'baz2' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 176 [[clang::suppress]] auto *baz_suppressed = provide_ref_ctnbl(); // no-warning 177 } 178 179 void func() { 180 RefCountable *bar = provide_ref_ctnbl(); 181 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 182 if (bar) 183 bar->method(); 184 } 185 }; 186 } // namespace auto_keyword 187 188 namespace guardian_casts { 189 void foo1() { 190 RefPtr<RefCountable> foo; 191 { 192 RefCountable *bar = downcast<RefCountable>(foo.get()); 193 bar->method(); 194 } 195 foo->method(); 196 } 197 198 void foo2() { 199 RefPtr<RefCountable> foo; 200 { 201 RefCountable *bar = 202 static_cast<RefCountable *>(downcast<RefCountable>(foo.get())); 203 someFunction(); 204 } 205 } 206 } // namespace guardian_casts 207 208 namespace guardian_ref_conversion_operator { 209 void foo() { 210 Ref<RefCountable> rc; 211 { 212 RefCountable &rr = rc; 213 rr.method(); 214 someFunction(); 215 } 216 } 217 } // namespace guardian_ref_conversion_operator 218 219 namespace ignore_for_if { 220 RefCountable *provide_ref_ctnbl() { return nullptr; } 221 222 void foo() { 223 // no warnings 224 if (RefCountable *a = provide_ref_ctnbl()) 225 a->trivial(); 226 for (RefCountable *b = provide_ref_ctnbl(); b != nullptr;) 227 b->trivial(); 228 RefCountable *array[1]; 229 for (RefCountable *c : array) 230 c->trivial(); 231 while (RefCountable *d = provide_ref_ctnbl()) 232 d->trivial(); 233 do { 234 RefCountable *e = provide_ref_ctnbl(); 235 e->trivial(); 236 } while (1); 237 someFunction(); 238 } 239 240 void bar() { 241 if (RefCountable *a = provide_ref_ctnbl()) { 242 // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 243 a->method(); 244 } 245 for (RefCountable *b = provide_ref_ctnbl(); b != nullptr;) { 246 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 247 b->method(); 248 } 249 RefCountable *array[1]; 250 for (RefCountable *c : array) { 251 // expected-warning@-1{{Local variable 'c' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 252 c->method(); 253 } 254 255 while (RefCountable *d = provide_ref_ctnbl()) { 256 // expected-warning@-1{{Local variable 'd' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 257 d->method(); 258 } 259 do { 260 RefCountable *e = provide_ref_ctnbl(); 261 // expected-warning@-1{{Local variable 'e' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 262 e->method(); 263 } while (1); 264 someFunction(); 265 } 266 267 } // namespace ignore_for_if 268 269 namespace ignore_system_headers { 270 271 RefCountable *provide_ref_ctnbl(); 272 273 void system_header() { 274 localVar<RefCountable>(provide_ref_ctnbl); 275 } 276 277 } // ignore_system_headers 278 279 namespace conditional_op { 280 RefCountable *provide_ref_ctnbl(); 281 bool bar(); 282 283 void foo() { 284 RefCountable *a = bar() ? nullptr : provide_ref_ctnbl(); 285 // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 286 RefPtr<RefCountable> b = provide_ref_ctnbl(); 287 { 288 RefCountable* c = bar() ? nullptr : b.get(); 289 c->method(); 290 RefCountable* d = bar() ? b.get() : nullptr; 291 d->method(); 292 } 293 } 294 295 } // namespace conditional_op 296 297 namespace local_assignment_basic { 298 299 RefCountable *provide_ref_cntbl(); 300 301 void foo(RefCountable* a) { 302 RefCountable* b = a; 303 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 304 if (b->trivial()) 305 b = provide_ref_cntbl(); 306 } 307 308 void bar(RefCountable* a) { 309 RefCountable* b; 310 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 311 b = provide_ref_cntbl(); 312 } 313 314 void baz() { 315 RefPtr a = provide_ref_cntbl(); 316 { 317 RefCountable* b = a.get(); 318 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 319 b = provide_ref_cntbl(); 320 } 321 } 322 323 } // namespace local_assignment_basic 324 325 namespace local_assignment_to_parameter { 326 327 RefCountable *provide_ref_cntbl(); 328 void someFunction(); 329 330 void foo(RefCountable* a) { 331 a = provide_ref_cntbl(); 332 // expected-warning@-1{{Assignment to an uncounted parameter 'a' is unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 333 someFunction(); 334 a->method(); 335 } 336 337 } // namespace local_assignment_to_parameter 338 339 namespace local_assignment_to_static_local { 340 341 RefCountable *provide_ref_cntbl(); 342 void someFunction(); 343 344 void foo() { 345 static RefCountable* a = nullptr; 346 // expected-warning@-1{{Static local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 347 a = provide_ref_cntbl(); 348 someFunction(); 349 a->method(); 350 } 351 352 } // namespace local_assignment_to_static_local 353 354 namespace local_assignment_to_global { 355 356 RefCountable *provide_ref_cntbl(); 357 void someFunction(); 358 359 RefCountable* g_a = nullptr; 360 // expected-warning@-1{{Global variable 'local_assignment_to_global::g_a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 361 362 void foo() { 363 g_a = provide_ref_cntbl(); 364 someFunction(); 365 g_a->method(); 366 } 367 368 } // namespace local_assignment_to_global 369 370 namespace local_refcountable_checkable_object { 371 372 RefCountableAndCheckable* provide_obj(); 373 374 void local_raw_ptr() { 375 RefCountableAndCheckable* a = nullptr; 376 // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 377 a = provide_obj(); 378 a->method(); 379 } 380 381 void local_checked_ptr() { 382 CheckedPtr<RefCountableAndCheckable> a = nullptr; 383 a = provide_obj(); 384 a->method(); 385 } 386 387 void local_var_with_guardian_checked_ptr() { 388 CheckedPtr<RefCountableAndCheckable> a = provide_obj(); 389 { 390 auto* b = a.get(); 391 b->method(); 392 } 393 } 394 395 void local_var_with_guardian_checked_ptr_with_assignment() { 396 CheckedPtr<RefCountableAndCheckable> a = provide_obj(); 397 { 398 RefCountableAndCheckable* b = a.get(); 399 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 400 b = provide_obj(); 401 b->method(); 402 } 403 } 404 405 void local_var_with_guardian_checked_ref() { 406 CheckedRef<RefCountableAndCheckable> a = *provide_obj(); 407 { 408 RefCountableAndCheckable& b = a; 409 b.method(); 410 } 411 } 412 413 void static_var() { 414 static RefCountableAndCheckable* a = nullptr; 415 // expected-warning@-1{{Static local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 416 a = provide_obj(); 417 } 418 419 } // namespace local_refcountable_checkable_object 420 421 namespace local_var_in_recursive_function { 422 423 struct TreeNode { 424 Ref<TreeNode> create() { return Ref(*new TreeNode); } 425 426 void ref() const { ++refCount; } 427 void deref() const { 428 if (!--refCount) 429 delete this; 430 } 431 432 int recursiveCost(); 433 int recursiveWeight(); 434 int weight(); 435 436 int cost { 0 }; 437 mutable unsigned refCount { 0 }; 438 TreeNode* nextSibling { nullptr }; 439 TreeNode* firstChild { nullptr }; 440 }; 441 442 int TreeNode::recursiveCost() { 443 // no warnings 444 unsigned totalCost = cost; 445 for (TreeNode* node = firstChild; node; node = node->nextSibling) 446 totalCost += recursiveCost(); 447 return totalCost; 448 } 449 450 int TreeNode::recursiveWeight() { 451 unsigned totalCost = weight(); 452 for (TreeNode* node = firstChild; node; node = node->nextSibling) 453 // expected-warning@-1{{Local variable 'node' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} 454 totalCost += recursiveWeight(); 455 return totalCost; 456 } 457 458 } // namespace local_var_in_recursive_function 459 460 namespace local_var_for_singleton { 461 RefCountable *singleton(); 462 RefCountable *otherSingleton(); 463 void foo() { 464 RefCountable* bar = singleton(); 465 RefCountable* baz = otherSingleton(); 466 } 467 }