495 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedLocalVarsChecker -verify %s2 3#include "mock-types.h"4#include "mock-system-header.h"5 6void someFunction();7 8namespace raw_ptr {9void foo() {10 RefCountable *bar;11 // FIXME: later on we might warn on uninitialized vars too12}13 14void bar(RefCountable *) {}15} // namespace raw_ptr16 17namespace reference {18void 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 26void foo_ref_trivial() {27 RefCountable automatic;28 RefCountable &bar = automatic;29}30 31void bar_ref(RefCountable &) {}32} // namespace reference33 34namespace guardian_scopes {35void foo1() {36 RefPtr<RefCountable> foo;37 { RefCountable *bar = foo.get(); }38}39 40void foo2() {41 RefPtr<RefCountable> foo;42 // missing embedded scope here43 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 49void foo3() {50 RefPtr<RefCountable> foo;51 {52 { RefCountable *bar = foo.get(); }53 }54}55 56void foo4() {57 {58 RefPtr<RefCountable> foo;59 { RefCountable *bar = foo.get(); }60 }61}62 63void foo5() {64 RefPtr<RefCountable> foo;65 auto* bar = foo.get();66 bar->trivial();67}68 69void 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 76struct SelfReferencingStruct {77 SelfReferencingStruct* ptr;78 RefCountable* obj { nullptr };79};80 81void foo7(RefCountable* obj) {82 SelfReferencingStruct bar = { &bar, obj };83 bar.obj->method();84}85 86void 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 foo = (RefCountable *)0;125 bar->method();126 }127}128 129void foo9(RefCountable& o) {130 Ref<RefCountable> guardian(o);131 {132 RefCountable &bar = guardian.get();133 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}134 guardian = o; // We don't detect that we're setting it to the same value.135 bar.method();136 }137 {138 RefCountable *bar = guardian.ptr();139 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}140 Ref<RefCountable> other(*bar); // We don't detect other has the same value as guardian.141 guardian.swap(other);142 bar->method();143 }144 {145 RefCountable *bar = guardian.ptr();146 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}147 Ref<RefCountable> other(static_cast<Ref<RefCountable>&&>(guardian));148 bar->method();149 }150 {151 RefCountable *bar = guardian.ptr();152 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}153 guardian.leakRef();154 bar->method();155 }156 {157 RefCountable *bar = guardian.ptr();158 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}159 guardian = o.trivial() ? o : *bar;160 bar->method();161 }162}163 164} // namespace guardian_scopes165 166namespace auto_keyword {167class Foo {168 RefCountable *provide_ref_ctnbl();169 170 void evil_func() {171 RefCountable *bar = provide_ref_ctnbl();172 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}173 auto *baz = provide_ref_ctnbl();174 // expected-warning@-1{{Local variable 'baz' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}175 auto *baz2 = this->provide_ref_ctnbl();176 // expected-warning@-1{{Local variable 'baz2' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}177 [[clang::suppress]] auto *baz_suppressed = provide_ref_ctnbl(); // no-warning178 }179 180 void func() {181 RefCountable *bar = provide_ref_ctnbl();182 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}183 if (bar)184 bar->method();185 }186};187} // namespace auto_keyword188 189namespace guardian_casts {190void foo1() {191 RefPtr<RefCountable> foo;192 {193 RefCountable *bar = downcast<RefCountable>(foo.get());194 bar->method();195 }196 foo->method();197}198 199void foo2() {200 RefPtr<RefCountable> foo;201 {202 RefCountable *bar =203 static_cast<RefCountable *>(downcast<RefCountable>(foo.get()));204 someFunction();205 }206}207} // namespace guardian_casts208 209namespace casts {210 211RefCountable* provide() { return nullptr; }212RefCountable* downcast(RefCountable*);213template<class T> T* bitwise_cast(T*);214template<class T> T* bit_cast(T*);215 216 void foo() {217 auto* cast1 = downcast(provide());218 auto* cast2 = bitwise_cast(provide());219 auto* cast3 = bit_cast(provide());220 }221} // namespace casts222 223namespace guardian_ref_conversion_operator {224void foo() {225 Ref<RefCountable> rc;226 {227 RefCountable &rr = rc;228 rr.method();229 someFunction();230 }231}232} // namespace guardian_ref_conversion_operator233 234namespace ignore_for_if {235RefCountable *provide_ref_ctnbl() { return nullptr; }236 237void foo() {238 // no warnings239 if (RefCountable *a = provide_ref_ctnbl())240 a->trivial();241 for (RefCountable *b = provide_ref_ctnbl(); b != nullptr;)242 b->trivial();243 RefCountable *array[1];244 for (RefCountable *c : array)245 c->trivial();246 while (RefCountable *d = provide_ref_ctnbl())247 d->trivial();248 do {249 RefCountable *e = provide_ref_ctnbl();250 e->trivial();251 } while (1);252 someFunction();253}254 255void bar() {256 if (RefCountable *a = provide_ref_ctnbl()) {257 // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}258 a->method(); 259 }260 for (RefCountable *b = provide_ref_ctnbl(); b != nullptr;) {261 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}262 b->method();263 }264 RefCountable *array[1];265 for (RefCountable *c : array) {266 // expected-warning@-1{{Local variable 'c' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}267 c->method();268 }269 270 while (RefCountable *d = provide_ref_ctnbl()) {271 // expected-warning@-1{{Local variable 'd' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}272 d->method();273 }274 do {275 RefCountable *e = provide_ref_ctnbl();276 // expected-warning@-1{{Local variable 'e' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}277 e->method();278 } while (1);279 someFunction();280}281 282} // namespace ignore_for_if283 284namespace ignore_system_headers {285 286RefCountable *provide_ref_ctnbl();287 288void system_header() {289 localVar<RefCountable>(provide_ref_ctnbl);290}291 292} // ignore_system_headers293 294namespace conditional_op {295RefCountable *provide_ref_ctnbl();296bool bar();297 298void foo() {299 RefCountable *a = bar() ? nullptr : provide_ref_ctnbl();300 // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}301 RefPtr<RefCountable> b = provide_ref_ctnbl();302 {303 RefCountable* c = bar() ? nullptr : b.get();304 c->method();305 RefCountable* d = bar() ? b.get() : nullptr;306 d->method();307 }308}309 310} // namespace conditional_op311 312namespace local_assignment_basic {313 314RefCountable *provide_ref_cntbl();315 316void foo(RefCountable* a) {317 RefCountable* b = a;318 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}319 if (b->trivial())320 b = provide_ref_cntbl();321}322 323void bar(RefCountable* a) {324 RefCountable* b;325 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}326 b = provide_ref_cntbl();327}328 329void baz() {330 RefPtr a = provide_ref_cntbl();331 {332 RefCountable* b = a.get();333 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}334 b = provide_ref_cntbl();335 }336}337 338} // namespace local_assignment_basic339 340namespace local_assignment_to_parameter {341 342RefCountable *provide_ref_cntbl();343void someFunction();344 345void foo(RefCountable* a) {346 a = provide_ref_cntbl();347 // expected-warning@-1{{Assignment to an uncounted parameter 'a' is unsafe [alpha.webkit.UncountedLocalVarsChecker]}}348 someFunction();349 a->method();350}351 352} // namespace local_assignment_to_parameter353 354namespace local_assignment_to_static_local {355 356RefCountable *provide_ref_cntbl();357void someFunction();358 359void foo() {360 static RefCountable* a = nullptr;361 // expected-warning@-1{{Static local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}362 a = provide_ref_cntbl();363 someFunction();364 a->method();365}366 367} // namespace local_assignment_to_static_local368 369namespace local_assignment_to_global {370 371RefCountable *provide_ref_cntbl();372void someFunction();373 374RefCountable* g_a = nullptr;375// expected-warning@-1{{Global variable 'local_assignment_to_global::g_a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}376 377void foo() {378 g_a = provide_ref_cntbl();379 someFunction();380 g_a->method();381}382 383} // namespace local_assignment_to_global384 385namespace local_refcountable_checkable_object {386 387RefCountableAndCheckable* provide_obj();388 389void local_raw_ptr() {390 RefCountableAndCheckable* a = nullptr;391 // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}392 a = provide_obj();393 a->method();394}395 396void local_checked_ptr() {397 CheckedPtr<RefCountableAndCheckable> a = nullptr;398 a = provide_obj();399 a->method();400}401 402void local_var_with_guardian_checked_ptr() {403 CheckedPtr<RefCountableAndCheckable> a = provide_obj();404 {405 auto* b = a.get();406 b->method();407 }408}409 410void local_var_with_guardian_checked_ptr_with_assignment() {411 CheckedPtr<RefCountableAndCheckable> a = provide_obj();412 {413 RefCountableAndCheckable* b = a.get();414 // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}415 b = provide_obj();416 b->method();417 }418}419 420void local_var_with_guardian_checked_ref() {421 CheckedRef<RefCountableAndCheckable> a = *provide_obj();422 {423 RefCountableAndCheckable& b = a;424 b.method();425 }426}427 428void static_var() {429 static RefCountableAndCheckable* a = nullptr;430 // expected-warning@-1{{Static local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}431 a = provide_obj();432}433 434} // namespace local_refcountable_checkable_object435 436namespace local_var_in_recursive_function {437 438struct TreeNode {439 Ref<TreeNode> create() { return Ref(*new TreeNode); }440 441 void ref() const { ++refCount; }442 void deref() const {443 if (!--refCount)444 delete this;445 }446 447 int recursiveCost();448 int recursiveWeight();449 int weight();450 451 int cost { 0 };452 mutable unsigned refCount { 0 };453 TreeNode* nextSibling { nullptr };454 TreeNode* firstChild { nullptr };455};456 457int TreeNode::recursiveCost() {458 // no warnings459 unsigned totalCost = cost;460 for (TreeNode* node = firstChild; node; node = node->nextSibling)461 totalCost += recursiveCost();462 return totalCost;463}464 465int TreeNode::recursiveWeight() {466 unsigned totalCost = weight();467 for (TreeNode* node = firstChild; node; node = node->nextSibling)468 // expected-warning@-1{{Local variable 'node' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}469 totalCost += recursiveWeight();470 return totalCost;471}472 473} // namespace local_var_in_recursive_function474 475namespace local_var_for_singleton {476 RefCountable *singleton();477 RefCountable *otherSingleton();478 void foo() {479 RefCountable* bar = singleton();480 RefCountable* baz = otherSingleton();481 }482}483 484namespace virtual_function {485 struct SomeObject {486 virtual RefCountable* provide() { return nullptr; }487 virtual RefCountable* operator&() { return nullptr; }488 };489 void foo(SomeObject* obj) {490 auto* bar = obj->provide();491 // expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}492 auto* baz = &*obj;493 // expected-warning@-1{{Local variable 'baz' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}494 }495}