443 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s2 3#include "mock-types.h"4 5RefCountable* provide();6void consume_refcntbl(RefCountable*);7void some_function();8 9namespace 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-warning19 }20}21 22namespace 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 30namespace 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 warning37 }38}39 40namespace 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 76namespace 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 111namespace null_ptr {112 void foo_ref() {113 consume_refcntbl(nullptr);114 consume_refcntbl(0);115 }116}117 118namespace 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 131namespace 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 148namespace 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*);177 template<class T> T* bitwise_cast(T*);178 template<class T> T* bit_cast(T*);179 180 void foo(RefCountable* param) {181 consume_ref_countable_ptr(downcast(param));182 consume_ref_countable_ptr(bitwise_cast(param));183 consume_ref_countable_ptr(bit_cast(param));184 }185 }186}187 188namespace 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 228namespace 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 272namespace 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 282namespace 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 305namespace 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 316namespace 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 327namespace 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 348namespace 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 362namespace call_with_explicit_construct_from_auto {363 364 struct Impl {365 void ref() const;366 void deref() const;367 368 static Ref<Impl> create();369 };370 371 template <typename T>372 struct ArgObj {373 T* t;374 };375 376 struct Object {377 Object();378 Object(Ref<Impl>&&);379 380 Impl* impl() const { return m_impl.get(); }381 382 static Object create(ArgObj<char>&) { return Impl::create(); }383 static void bar(Impl&);384 385 private:386 RefPtr<Impl> m_impl;387 };388 389 template<typename CharacterType> void foo()390 {391 auto result = Object::create(ArgObj<CharacterType> { });392 Object::bar(Ref { *result.impl() });393 }394 395}396 397namespace call_with_explicit_temporary_obj {398 void foo() {399 Ref { *provide() }->method();400 RefPtr { provide() }->method();401 }402 template <typename T>403 void bar() {404 Ref(*provide())->method();405 RefPtr(provide())->method();406 }407 void baz() {408 bar<int>();409 }410 411 class Foo {412 Ref<RefCountable> ensure();413 void foo() {414 Ref { ensure() }->method();415 }416 };417 418 void baz(Ref<RefCountable>&& arg) {419 Ref { arg }->method();420 }421}422 423namespace call_with_explicit_construct {424}425 426namespace call_with_adopt_ref {427 class Obj {428 public:429 void ref() const;430 void deref() const;431 void method();432 };433 434 // This is needed due to rdar://141692212.435 struct dummy {436 RefPtr<Obj> any;437 };438 439 void foo() {440 adoptRef(new Obj)->method();441 }442}443