xref: /llvm-project/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp (revision 05860f9b384b9b8f8bb01fa8984dbc2833669a27)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
2 
3 #include "mock-types.h"
4 
5 CheckedObj* provide();
6 void consume_refcntbl(CheckedObj*);
7 void some_function();
8 
9 namespace simple {
10   void foo() {
11     consume_refcntbl(provide());
12     // expected-warning@-1{{Call argument is unchecked 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, CheckedObj* foo, bool);
24   void foo() {
25     consume_refcntbl(42, provide(), true);
26     // expected-warning@-1{{Call argument for parameter 'foo' is unchecked and unsafe}}
27   }
28 }
29 
30 namespace ref_counted {
31   CheckedRef<CheckedObj> provide_ref_counted() { return CheckedRef<CheckedObj>{}; }
32   void consume_ref_counted(CheckedRef<CheckedObj>) {}
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(CheckedObj* ptr);
43     void consume_ref(const CheckedObj& 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 unchecked and unsafe}}
51     c.consume_ref(*provide());
52     // expected-warning@-1{{Call argument for parameter 'ref' is unchecked and unsafe}}
53   }
54 
55   void foo2() {
56     struct Consumer {
57       void consume(CheckedObj*) { some_function(); }
58       void whatever() {
59         consume(provide());
60         // expected-warning@-1{{Call argument is unchecked and unsafe}}
61       }
62     };
63   }
64 
65   void foo3() {
66     struct Consumer {
67       void consume(CheckedObj*) { some_function(); }
68       void whatever() {
69         this->consume(provide());
70         // expected-warning@-1{{Call argument is unchecked and unsafe}}
71       }
72     };
73   }
74 }
75 
76 namespace casts {
77   CheckedObj* downcast(CheckedObj*);
78 
79   void foo() {
80     consume_refcntbl(provide());
81     // expected-warning@-1{{Call argument is unchecked and unsafe}}
82 
83     consume_refcntbl(static_cast<CheckedObj*>(provide()));
84     // expected-warning@-1{{Call argument is unchecked and unsafe}}
85 
86     consume_refcntbl(dynamic_cast<CheckedObj*>(provide()));
87     // expected-warning@-1{{Call argument is unchecked and unsafe}}
88 
89     consume_refcntbl(const_cast<CheckedObj*>(provide()));
90     // expected-warning@-1{{Call argument is unchecked and unsafe}}
91 
92     consume_refcntbl(reinterpret_cast<CheckedObj*>(provide()));
93     // expected-warning@-1{{Call argument is unchecked and unsafe}}
94 
95     consume_refcntbl(downcast(provide()));
96     // expected-warning@-1{{Call argument is unchecked and unsafe}}
97 
98     consume_refcntbl(
99       static_cast<CheckedObj*>(
100         downcast(
101           static_cast<CheckedObj*>(
102             provide()
103           )
104         )
105       )
106     );
107     // expected-warning@-8{{Call argument is unchecked 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     CheckedObj* get();
121   };
122 
123   void foo() {
124     Decoy D;
125 
126     consume_refcntbl(D.get());
127     // expected-warning@-1{{Call argument is unchecked 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(CheckedObj&) {}
141 
142   void foo() {
143     CheckedRef<CheckedObj> bar;
144     consume_ref(bar);
145   }
146 }
147 
148 namespace param_formarding_function {
149   void consume_ref_countable_ref(CheckedObj&);
150   void consume_ref_countable_ptr(CheckedObj*);
151 
152   namespace ptr {
153     void foo(CheckedObj* param) {
154       consume_ref_countable_ptr(param);
155     }
156   }
157 
158   namespace ref {
159     void foo(CheckedObj& param) {
160       consume_ref_countable_ref(param);
161     }
162   }
163 
164   namespace ref_deref_operators {
165     void foo_ref(CheckedObj& param) {
166       consume_ref_countable_ptr(&param);
167     }
168 
169     void foo_ptr(CheckedObj* param) {
170       consume_ref_countable_ref(*param);
171     }
172   }
173 
174   namespace casts {
175 
176   CheckedObj* downcast(CheckedObj*) { return nullptr; }
177 
178   template<class T>
179   T* bitwise_cast(T*) { return nullptr; }
180 
181     void foo(CheckedObj* 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 = [](CheckedObj&) { some_function(); };
190   auto consume_ref_countable_ptr = [](CheckedObj*) { some_function(); };
191 
192   namespace ptr {
193     void foo(CheckedObj* param) {
194       consume_ref_countable_ptr(param);
195     }
196   }
197 
198   namespace ref {
199     void foo(CheckedObj& param) {
200       consume_ref_countable_ref(param);
201     }
202   }
203 
204   namespace ref_deref_operators {
205     void foo_ref(CheckedObj& param) {
206       consume_ref_countable_ptr(&param);
207     }
208 
209     void foo_ptr(CheckedObj* param) {
210       consume_ref_countable_ref(*param);
211     }
212   }
213 
214   namespace casts {
215 
216   CheckedObj* downcast(CheckedObj*) { return nullptr; }
217 
218   template<class T>
219   T* bitwise_cast(T*) { return nullptr; }
220 
221     void foo(CheckedObj* 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(CheckedObj&) {};
231     static void consume_ref_countable_ptr(CheckedObj*) {};
232   };
233 
234   namespace ptr {
235     void foo(CheckedObj* param) {
236       methodclass::consume_ref_countable_ptr(param);
237      }
238   }
239 
240   namespace ref {
241     void foo(CheckedObj& param) {
242       methodclass mc;
243       mc.consume_ref_countable_ref(param);
244      }
245   }
246 
247   namespace ref_deref_operators {
248     void foo_ref(CheckedObj& param) {
249       methodclass::consume_ref_countable_ptr(&param);
250      }
251 
252     void foo_ptr(CheckedObj* param) {
253       methodclass mc;
254       mc.consume_ref_countable_ref(*param);
255      }
256   }
257 
258   namespace casts {
259 
260   CheckedObj* downcast(CheckedObj*) { return nullptr; }
261 
262   template<class T>
263   T* bitwise_cast(T*) { return nullptr; }
264 
265     void foo(CheckedObj* 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(CheckedObj*) {}
274   CheckedObj* downcast(CheckedObj*) { return nullptr; }
275 
276   void foo() {
277     CheckedPtr<CheckedObj> bar;
278     consume_ref_countable( downcast(bar.get()) );
279   }
280 }
281 
282 namespace string_impl {
283   struct String {
284     CheckedObj* impl() { return nullptr; }
285   };
286 
287   struct AtomString {
288     CheckedObj rc;
289     CheckedObj& impl() { return rc; }
290   };
291 
292   void consume_ptr(CheckedObj*) {}
293   void consume_ref(CheckedObj&) {}
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   CheckedObj* global;
307 
308   void function_with_default_arg(CheckedObj* param = global);
309   // expected-warning@-1{{Call argument for parameter 'param' is unchecked and unsafe}}
310 
311   void foo() {
312     function_with_default_arg();
313   }
314 }
315 
316 namespace cxx_member_func {
317   CheckedRef<CheckedObj> provideProtected();
318   void foo() {
319     provide()->trivial();
320     provide()->method();
321     // expected-warning@-1{{Call argument for 'this' parameter is unchecked 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+(CheckedObj* bad);
331     friend Foo& operator-(Foo& lhs, CheckedObj* bad);
332     void operator()(CheckedObj* bad);
333   };
334 
335   CheckedObj* global;
336 
337   void foo() {
338     Foo f;
339     f + global;
340     // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
341     f - global;
342     // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
343     f(global);
344     // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
345   }
346 }
347 
348 namespace call_with_ptr_on_ref {
349   CheckedRef<CheckedObj> provideProtected();
350   void bar(CheckedObj* 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 unchecked and unsafe}}
357     bar(v ? provideProtected().ptr() : provide());
358     // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
359   }
360 }
361 
362 namespace call_with_explicit_temporary_obj {
363   void foo() {
364     CheckedRef { *provide() }->method();
365     CheckedPtr { provide() }->method();
366   }
367 }
368 
369 namespace call_with_checked_ptr {
370 
371   class Foo : public CheckedObj {
372   public:
373     CheckedPtr<CheckedObj> obj1() { return m_obj; }
374     CheckedRef<CheckedObj> obj2() { return *m_obj; }
375   private:
376     CheckedObj* m_obj;
377   };
378 
379   Foo* getFoo();
380 
381   void bar() {
382     getFoo()->obj1()->method();
383     getFoo()->obj2()->method();
384   }
385 
386 }
387