1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2 
3 #include "mock-types.h"
4 
provide()5 RefCountable* provide() { return nullptr; }
consume_refcntbl(RefCountable *)6 void consume_refcntbl(RefCountable*) {}
7 
8 namespace simple {
foo()9   void foo() {
10     consume_refcntbl(provide());
11     // expected-warning@-1{{Call argument is uncounted and unsafe}}
12   }
13 }
14 
15 namespace multi_arg {
consume_refcntbl(int,RefCountable * foo,bool)16   void consume_refcntbl(int, RefCountable* foo, bool) {}
foo()17   void foo() {
18     consume_refcntbl(42, provide(), true);
19     // expected-warning@-1{{Call argument for parameter 'foo' is uncounted and unsafe}}
20   }
21 }
22 
23 namespace ref_counted {
provide_ref_counted()24   Ref<RefCountable> provide_ref_counted() { return Ref<RefCountable>{}; }
consume_ref_counted(Ref<RefCountable>)25   void consume_ref_counted(Ref<RefCountable>) {}
26 
foo()27   void foo() {
28     consume_refcntbl(provide_ref_counted().get());
29     // no warning
30   }
31 }
32 
33 namespace methods {
34   struct Consumer {
consume_ptrmethods::Consumer35     void consume_ptr(RefCountable* ptr) {}
consume_refmethods::Consumer36     void consume_ref(const RefCountable& ref) {}
37   };
38 
foo()39   void foo() {
40     Consumer c;
41 
42     c.consume_ptr(provide());
43     // expected-warning@-1{{Call argument for parameter 'ptr' is uncounted and unsafe}}
44     c.consume_ref(*provide());
45     // expected-warning@-1{{Call argument for parameter 'ref' is uncounted and unsafe}}
46   }
47 
foo2()48   void foo2() {
49     struct Consumer {
50       void consume(RefCountable*) { }
51       void whatever() {
52         consume(provide());
53         // expected-warning@-1{{Call argument is uncounted and unsafe}}
54       }
55     };
56   }
57 
foo3()58   void foo3() {
59     struct Consumer {
60       void consume(RefCountable*) { }
61       void whatever() {
62         this->consume(provide());
63         // expected-warning@-1{{Call argument is uncounted and unsafe}}
64       }
65     };
66   }
67 }
68 
69 namespace casts {
downcast(RefCountable *)70   RefCountable* downcast(RefCountable*) { return nullptr; }
71 
foo()72   void foo() {
73     consume_refcntbl(provide());
74     // expected-warning@-1{{Call argument is uncounted and unsafe}}
75 
76     consume_refcntbl(static_cast<RefCountable*>(provide()));
77     // expected-warning@-1{{Call argument is uncounted and unsafe}}
78 
79     consume_refcntbl(dynamic_cast<RefCountable*>(provide()));
80     // expected-warning@-1{{Call argument is uncounted and unsafe}}
81 
82     consume_refcntbl(const_cast<RefCountable*>(provide()));
83     // expected-warning@-1{{Call argument is uncounted and unsafe}}
84 
85     consume_refcntbl(reinterpret_cast<RefCountable*>(provide()));
86     // expected-warning@-1{{Call argument is uncounted and unsafe}}
87 
88     consume_refcntbl(downcast(provide()));
89     // expected-warning@-1{{Call argument is uncounted and unsafe}}
90 
91     consume_refcntbl(
92       static_cast<RefCountable*>(
93         downcast(
94           static_cast<RefCountable*>(
95             provide()
96           )
97         )
98       )
99     );
100     // expected-warning@-8{{Call argument is uncounted and unsafe}}
101   }
102 }
103 
104 namespace null_ptr {
foo_ref()105   void foo_ref() {
106     consume_refcntbl(nullptr);
107     consume_refcntbl(0);
108   }
109 }
110 
111 namespace ref_counted_lookalike {
112   struct Decoy {
getref_counted_lookalike::Decoy113     RefCountable* get() { return nullptr; }
114   };
115 
foo()116   void foo() {
117     Decoy D;
118 
119     consume_refcntbl(D.get());
120     // expected-warning@-1{{Call argument is uncounted and unsafe}}
121   }
122 }
123 
124 namespace Ref_to_reference_conversion_operator {
125   template<typename T> struct Ref {
126     Ref() = default;
RefRef_to_reference_conversion_operator::Ref127     Ref(T*) { }
getRef_to_reference_conversion_operator::Ref128     T* get() { return nullptr; }
operator T&Ref_to_reference_conversion_operator::Ref129     operator T& () { return t; }
130     T t;
131   };
132 
consume_ref(RefCountable &)133   void consume_ref(RefCountable&) {}
134 
foo()135   void foo() {
136     Ref<RefCountable> bar;
137     consume_ref(bar);
138   }
139 }
140 
141 namespace param_formarding_function {
consume_ref_countable_ref(RefCountable &)142   void consume_ref_countable_ref(RefCountable&) {}
consume_ref_countable_ptr(RefCountable *)143   void consume_ref_countable_ptr(RefCountable*) {}
144 
145   namespace ptr {
foo(RefCountable * param)146     void foo(RefCountable* param) {
147       consume_ref_countable_ptr(param);
148     }
149   }
150 
151   namespace ref {
foo(RefCountable & param)152     void foo(RefCountable& param) {
153       consume_ref_countable_ref(param);
154     }
155   }
156 
157   namespace ref_deref_operators {
foo_ref(RefCountable & param)158     void foo_ref(RefCountable& param) {
159       consume_ref_countable_ptr(&param);
160     }
161 
foo_ptr(RefCountable * param)162     void foo_ptr(RefCountable* param) {
163       consume_ref_countable_ref(*param);
164     }
165   }
166 
167   namespace casts {
168 
downcast(RefCountable *)169   RefCountable* downcast(RefCountable*) { return nullptr; }
170 
171   template<class T>
bitwise_cast(T *)172   T* bitwise_cast(T*) { return nullptr; }
173 
foo(RefCountable * param)174     void foo(RefCountable* param) {
175       consume_ref_countable_ptr(downcast(param));
176       consume_ref_countable_ptr(bitwise_cast(param));
177      }
178   }
179 }
180 
181 namespace param_formarding_lambda {
__anondd0dcd640102(RefCountable&) 182   auto consume_ref_countable_ref = [](RefCountable&) {};
__anondd0dcd640202(RefCountable*) 183   auto consume_ref_countable_ptr = [](RefCountable*) {};
184 
185   namespace ptr {
foo(RefCountable * param)186     void foo(RefCountable* param) {
187       consume_ref_countable_ptr(param);
188     }
189   }
190 
191   namespace ref {
foo(RefCountable & param)192     void foo(RefCountable& param) {
193       consume_ref_countable_ref(param);
194     }
195   }
196 
197   namespace ref_deref_operators {
foo_ref(RefCountable & param)198     void foo_ref(RefCountable& param) {
199       consume_ref_countable_ptr(&param);
200     }
201 
foo_ptr(RefCountable * param)202     void foo_ptr(RefCountable* param) {
203       consume_ref_countable_ref(*param);
204     }
205   }
206 
207   namespace casts {
208 
downcast(RefCountable *)209   RefCountable* downcast(RefCountable*) { return nullptr; }
210 
211   template<class T>
bitwise_cast(T *)212   T* bitwise_cast(T*) { return nullptr; }
213 
foo(RefCountable * param)214     void foo(RefCountable* param) {
215       consume_ref_countable_ptr(downcast(param));
216       consume_ref_countable_ptr(bitwise_cast(param));
217     }
218   }
219 }
220 
221 namespace param_forwarding_method {
222   struct methodclass {
consume_ref_countable_refparam_forwarding_method::methodclass223     void consume_ref_countable_ref(RefCountable&) {};
consume_ref_countable_ptrparam_forwarding_method::methodclass224     static void consume_ref_countable_ptr(RefCountable*) {};
225   };
226 
227   namespace ptr {
foo(RefCountable * param)228     void foo(RefCountable* param) {
229       methodclass::consume_ref_countable_ptr(param);
230      }
231   }
232 
233   namespace ref {
foo(RefCountable & param)234     void foo(RefCountable& param) {
235       methodclass mc;
236       mc.consume_ref_countable_ref(param);
237      }
238   }
239 
240   namespace ref_deref_operators {
foo_ref(RefCountable & param)241     void foo_ref(RefCountable& param) {
242       methodclass::consume_ref_countable_ptr(&param);
243      }
244 
foo_ptr(RefCountable * param)245     void foo_ptr(RefCountable* param) {
246       methodclass mc;
247       mc.consume_ref_countable_ref(*param);
248      }
249   }
250 
251   namespace casts {
252 
downcast(RefCountable *)253   RefCountable* downcast(RefCountable*) { return nullptr; }
254 
255   template<class T>
bitwise_cast(T *)256   T* bitwise_cast(T*) { return nullptr; }
257 
foo(RefCountable * param)258     void foo(RefCountable* param) {
259       methodclass::consume_ref_countable_ptr(downcast(param));
260        methodclass::consume_ref_countable_ptr(bitwise_cast(param));
261      }
262   }
263 }
264 
265 namespace make_ref {
makeRef(RefCountable *)266   void makeRef(RefCountable*) {}
makeRefPtr(RefCountable *)267   void makeRefPtr(RefCountable*) {}
makeWeakPtr(RefCountable *)268   void makeWeakPtr(RefCountable*) {}
makeWeakPtr(RefCountable &)269   void makeWeakPtr(RefCountable&) {}
270 
foo()271   void foo() {
272     makeRef(provide());
273     makeRefPtr(provide());
274     RefPtr<RefCountable> a(provide());
275     Ref<RefCountable> b(provide());
276     makeWeakPtr(provide());
277     makeWeakPtr(*provide());
278   }
279 }
280 
281 namespace downcast {
consume_ref_countable(RefCountable *)282   void consume_ref_countable(RefCountable*) {}
downcast(RefCountable *)283   RefCountable* downcast(RefCountable*) { return nullptr; }
284 
foo()285   void foo() {
286     RefPtr<RefCountable> bar;
287     consume_ref_countable( downcast(bar.get()) );
288   }
289 }
290 
291 namespace string_impl {
292   struct String {
implstring_impl::String293     RefCountable* impl() { return nullptr; }
294   };
295 
296   struct AtomString {
297     RefCountable rc;
implstring_impl::AtomString298     RefCountable& impl() { return rc; }
299   };
300 
consume_ptr(RefCountable *)301   void consume_ptr(RefCountable*) {}
consume_ref(RefCountable &)302   void consume_ref(RefCountable&) {}
303 
304   namespace simple {
foo()305     void foo() {
306       String s;
307       AtomString as;
308       consume_ptr(s.impl());
309       consume_ref(as.impl());
310     }
311   }
312 }
313 
314 namespace default_arg {
315   RefCountable* global;
316 
function_with_default_arg(RefCountable * param=global)317   void function_with_default_arg(RefCountable* param = global) {}
318   // expected-warning@-1{{Call argument for parameter 'param' is uncounted and unsafe}}
319 
foo()320   void foo() {
321     function_with_default_arg();
322   }
323 }
324 
325 namespace cxx_member_operator_call {
326   // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.
327   struct Foo {
operator +cxx_member_operator_call::Foo328     Foo& operator+(RefCountable* bad) { return *this; }
operator -(Foo & lhs,RefCountable * bad)329     friend Foo& operator-(Foo& lhs, RefCountable* bad) { return lhs; }
operator ()cxx_member_operator_call::Foo330     void operator()(RefCountable* bad) { }
331   };
332 
333   RefCountable* global;
334 
foo()335   void foo() {
336     Foo f;
337     f + global;
338     // expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
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   }
344 }
345