xref: /llvm-project/clang/test/Analysis/Checkers/WebKit/call-args.cpp (revision d3c4637cbbd5f0a84811abe195098ce714a2cc32)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2 
3 #include "mock-types.h"
4 
5 RefCountable* provide();
6 void consume_refcntbl(RefCountable*);
7 void some_function();
8 
9 namespace simple {
10   void foo() {
11     consume_refcntbl(provide());
12     // expected-warning@-1{{Call argument is uncounted and unsafe}}
13   }
14 
15   // Test that the checker works with [[clang::suppress]].
16   void foo_suppressed() {
17     [[clang::suppress]]
18     consume_refcntbl(provide()); // no-warning
19   }
20 }
21 
22 namespace multi_arg {
23   void consume_refcntbl(int, RefCountable* foo, bool);
24   void foo() {
25     consume_refcntbl(42, provide(), true);
26     // expected-warning@-1{{Call argument for parameter 'foo' is uncounted and unsafe}}
27   }
28 }
29 
30 namespace ref_counted {
31   Ref<RefCountable> provide_ref_counted() { return Ref<RefCountable>{}; }
32   void consume_ref_counted(Ref<RefCountable>) {}
33 
34   void foo() {
35     consume_refcntbl(provide_ref_counted().ptr());
36     // no warning
37   }
38 }
39 
40 namespace methods {
41   struct Consumer {
42     void consume_ptr(RefCountable* ptr);
43     void consume_ref(const RefCountable& ref);
44   };
45 
46   void foo() {
47     Consumer c;
48 
49     c.consume_ptr(provide());
50     // expected-warning@-1{{Call argument for parameter 'ptr' is uncounted and unsafe}}
51     c.consume_ref(*provide());
52     // expected-warning@-1{{Call argument for parameter 'ref' is uncounted and unsafe}}
53   }
54 
55   void foo2() {
56     struct Consumer {
57       void consume(RefCountable*) { some_function(); }
58       void whatever() {
59         consume(provide());
60         // expected-warning@-1{{Call argument is uncounted and unsafe}}
61       }
62     };
63   }
64 
65   void foo3() {
66     struct Consumer {
67       void consume(RefCountable*) { some_function(); }
68       void whatever() {
69         this->consume(provide());
70         // expected-warning@-1{{Call argument is uncounted and unsafe}}
71       }
72     };
73   }
74 }
75 
76 namespace casts {
77   RefCountable* downcast(RefCountable*);
78 
79   void foo() {
80     consume_refcntbl(provide());
81     // expected-warning@-1{{Call argument is uncounted and unsafe}}
82 
83     consume_refcntbl(static_cast<RefCountable*>(provide()));
84     // expected-warning@-1{{Call argument is uncounted and unsafe}}
85 
86     consume_refcntbl(dynamic_cast<RefCountable*>(provide()));
87     // expected-warning@-1{{Call argument is uncounted and unsafe}}
88 
89     consume_refcntbl(const_cast<RefCountable*>(provide()));
90     // expected-warning@-1{{Call argument is uncounted and unsafe}}
91 
92     consume_refcntbl(reinterpret_cast<RefCountable*>(provide()));
93     // expected-warning@-1{{Call argument is uncounted and unsafe}}
94 
95     consume_refcntbl(downcast(provide()));
96     // expected-warning@-1{{Call argument is uncounted and unsafe}}
97 
98     consume_refcntbl(
99       static_cast<RefCountable*>(
100         downcast(
101           static_cast<RefCountable*>(
102             provide()
103           )
104         )
105       )
106     );
107     // expected-warning@-8{{Call argument is uncounted and unsafe}}
108   }
109 }
110 
111 namespace null_ptr {
112   void foo_ref() {
113     consume_refcntbl(nullptr);
114     consume_refcntbl(0);
115   }
116 }
117 
118 namespace ref_counted_lookalike {
119   struct Decoy {
120     RefCountable* get();
121   };
122 
123   void foo() {
124     Decoy D;
125 
126     consume_refcntbl(D.get());
127     // expected-warning@-1{{Call argument is uncounted and unsafe}}
128   }
129 }
130 
131 namespace Ref_to_reference_conversion_operator {
132   template<typename T> struct Ref {
133     Ref() = default;
134     Ref(T*) { }
135     T* get() { return nullptr; }
136     operator T& () { return t; }
137     T t;
138   };
139 
140   void consume_ref(RefCountable&) {}
141 
142   void foo() {
143     Ref<RefCountable> bar;
144     consume_ref(bar);
145   }
146 }
147 
148 namespace param_formarding_function {
149   void consume_ref_countable_ref(RefCountable&);
150   void consume_ref_countable_ptr(RefCountable*);
151 
152   namespace ptr {
153     void foo(RefCountable* param) {
154       consume_ref_countable_ptr(param);
155     }
156   }
157 
158   namespace ref {
159     void foo(RefCountable& param) {
160       consume_ref_countable_ref(param);
161     }
162   }
163 
164   namespace ref_deref_operators {
165     void foo_ref(RefCountable& param) {
166       consume_ref_countable_ptr(&param);
167     }
168 
169     void foo_ptr(RefCountable* param) {
170       consume_ref_countable_ref(*param);
171     }
172   }
173 
174   namespace casts {
175 
176   RefCountable* downcast(RefCountable*) { return nullptr; }
177 
178   template<class T>
179   T* bitwise_cast(T*) { return nullptr; }
180 
181     void foo(RefCountable* param) {
182       consume_ref_countable_ptr(downcast(param));
183       consume_ref_countable_ptr(bitwise_cast(param));
184      }
185   }
186 }
187 
188 namespace param_formarding_lambda {
189   auto consume_ref_countable_ref = [](RefCountable&) { some_function(); };
190   auto consume_ref_countable_ptr = [](RefCountable*) { some_function(); };
191 
192   namespace ptr {
193     void foo(RefCountable* param) {
194       consume_ref_countable_ptr(param);
195     }
196   }
197 
198   namespace ref {
199     void foo(RefCountable& param) {
200       consume_ref_countable_ref(param);
201     }
202   }
203 
204   namespace ref_deref_operators {
205     void foo_ref(RefCountable& param) {
206       consume_ref_countable_ptr(&param);
207     }
208 
209     void foo_ptr(RefCountable* param) {
210       consume_ref_countable_ref(*param);
211     }
212   }
213 
214   namespace casts {
215 
216   RefCountable* downcast(RefCountable*) { return nullptr; }
217 
218   template<class T>
219   T* bitwise_cast(T*) { return nullptr; }
220 
221     void foo(RefCountable* param) {
222       consume_ref_countable_ptr(downcast(param));
223       consume_ref_countable_ptr(bitwise_cast(param));
224     }
225   }
226 }
227 
228 namespace param_forwarding_method {
229   struct methodclass {
230     void consume_ref_countable_ref(RefCountable&) {};
231     static void consume_ref_countable_ptr(RefCountable*) {};
232   };
233 
234   namespace ptr {
235     void foo(RefCountable* param) {
236       methodclass::consume_ref_countable_ptr(param);
237      }
238   }
239 
240   namespace ref {
241     void foo(RefCountable& param) {
242       methodclass mc;
243       mc.consume_ref_countable_ref(param);
244      }
245   }
246 
247   namespace ref_deref_operators {
248     void foo_ref(RefCountable& param) {
249       methodclass::consume_ref_countable_ptr(&param);
250      }
251 
252     void foo_ptr(RefCountable* param) {
253       methodclass mc;
254       mc.consume_ref_countable_ref(*param);
255      }
256   }
257 
258   namespace casts {
259 
260   RefCountable* downcast(RefCountable*) { return nullptr; }
261 
262   template<class T>
263   T* bitwise_cast(T*) { return nullptr; }
264 
265     void foo(RefCountable* param) {
266       methodclass::consume_ref_countable_ptr(downcast(param));
267        methodclass::consume_ref_countable_ptr(bitwise_cast(param));
268      }
269   }
270 }
271 
272 namespace downcast {
273   void consume_ref_countable(RefCountable*) {}
274   RefCountable* downcast(RefCountable*) { return nullptr; }
275 
276   void foo() {
277     RefPtr<RefCountable> bar;
278     consume_ref_countable( downcast(bar.get()) );
279   }
280 }
281 
282 namespace string_impl {
283   struct String {
284     RefCountable* impl() { return nullptr; }
285   };
286 
287   struct AtomString {
288     RefCountable rc;
289     RefCountable& impl() { return rc; }
290   };
291 
292   void consume_ptr(RefCountable*) {}
293   void consume_ref(RefCountable&) {}
294 
295   namespace simple {
296     void foo() {
297       String s;
298       AtomString as;
299       consume_ptr(s.impl());
300       consume_ref(as.impl());
301     }
302   }
303 }
304 
305 namespace default_arg {
306   RefCountable* global;
307 
308   void function_with_default_arg(RefCountable* param = global);
309   // expected-warning@-1{{Call argument for parameter 'param' is uncounted and unsafe}}
310 
311   void foo() {
312     function_with_default_arg();
313   }
314 }
315 
316 namespace cxx_member_func {
317   Ref<RefCountable> provideProtected();
318   void foo() {
319     provide()->trivial();
320     provide()->method();
321     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
322     provideProtected()->method();
323     (provideProtected())->method();
324   };
325 }
326 
327 namespace cxx_member_operator_call {
328   // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.
329   struct Foo {
330     Foo& operator+(RefCountable* bad);
331     friend Foo& operator-(Foo& lhs, RefCountable* bad);
332     void operator()(RefCountable* bad);
333   };
334 
335   RefCountable* global;
336 
337   void foo() {
338     Foo f;
339     f + global;
340     // expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
341     f - global;
342     // expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
343     f(global);
344     // expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
345   }
346 }
347 
348 namespace call_with_ptr_on_ref {
349   Ref<RefCountable> provideProtected();
350   void bar(RefCountable* bad);
351   bool baz();
352   void foo(bool v) {
353     bar(v ? nullptr : provideProtected().ptr());
354     bar(baz() ? provideProtected().ptr() : nullptr);
355     bar(v ? provide() : provideProtected().ptr());
356     // expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
357     bar(v ? provideProtected().ptr() : provide());
358     // expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
359   }
360 }
361 
362 namespace call_with_explicit_temporary_obj {
363   void foo() {
364     Ref { *provide() }->method();
365     RefPtr { provide() }->method();
366   }
367   template <typename T>
368   void bar() {
369     Ref(*provide())->method();
370     RefPtr(provide())->method();
371   }
372   void baz() {
373     bar<int>();
374   }
375 }
376 
377 namespace call_with_explicit_construct {
378 }
379 
380 namespace call_with_adopt_ref {
381   class Obj {
382   public:
383     void ref() const;
384     void deref() const;
385     void method();
386   };
387 
388   // This is needed due to rdar://141692212.
389   struct dummy {
390     RefPtr<Obj> any;
391   };
392 
393   void foo() {
394     adoptRef(new Obj)->method();
395   }
396 }
397