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(¶m); 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(¶m); 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(¶m); 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