xref: /llvm-project/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp (revision 377d1f0a6b862183b25701cc765fca7f84ea8e32)
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 }