brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.0 KiB · fd1eecd Raw
655 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.UncountedLambdaCapturesChecker -verify %s2 3#include "mock-types.h"4 5namespace std {6 7template <typename T>8T&& move(T& t) {9  return static_cast<T&&>(t);10}11 12namespace ranges {13 14template<typename IteratorType, typename CallbackType>15void for_each(IteratorType first, IteratorType last, CallbackType callback) {16  for (auto it = first; !(it == last); ++it)17    callback(*it);18}19 20struct all_of_impl {21  template <typename Collection, typename Predicate>22  constexpr bool operator()(const Collection& collection, Predicate predicate) const {23    for (auto it = collection.begin(); it != collection.end(); ++it) {24      if (!predicate(*it))25        return false;26    }27    return true;28  }29};30inline constexpr auto all_of = all_of_impl {};31 32}33 34}35 36namespace WTF {37 38namespace Detail {39 40template<typename Out, typename... In>41class CallableWrapperBase {42public:43    virtual ~CallableWrapperBase() { }44    virtual Out call(In...) = 0;45};46 47template<typename, typename, typename...> class CallableWrapper;48 49template<typename CallableType, typename Out, typename... In>50class CallableWrapper : public CallableWrapperBase<Out, In...> {51public:52    explicit CallableWrapper(CallableType& callable)53        : m_callable(callable) { }54    Out call(In... in) final { return m_callable(in...); }55 56private:57    CallableType m_callable;58};59 60} // namespace Detail61 62template<typename> class Function;63 64template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*);65 66template <typename Out, typename... In>67class Function<Out(In...)> {68public:69    using Impl = Detail::CallableWrapperBase<Out, In...>;70 71    Function() = default;72 73    template<typename FunctionType>74    Function(FunctionType f)75        : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>(f)) { }76 77    Out operator()(In... in) const { return m_callableWrapper->call(in...); }78    explicit operator bool() const { return !!m_callableWrapper; }79 80private:81    enum AdoptTag { Adopt };82    Function(Impl* impl, AdoptTag)83        : m_callableWrapper(impl)84    {85    }86 87    friend Function adopt<Out, In...>(Impl*);88 89    std::unique_ptr<Impl> m_callableWrapper;90};91 92template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl)93{94    return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);95}96 97template <typename KeyType, typename ValueType>98class HashMap {99public:100  HashMap();101  HashMap([[clang::noescape]] const Function<ValueType()>&);102  void ensure(const KeyType&, [[clang::noescape]] const Function<ValueType()>&);103  bool operator+([[clang::noescape]] const Function<ValueType()>&) const;104  static void ifAny(HashMap, [[clang::noescape]] const Function<bool(ValueType)>&);105 106private:107  ValueType* m_table { nullptr };108};109 110class ScopeExit final {111public:112  template<typename ExitFunctionParameter>113  explicit ScopeExit(ExitFunctionParameter&& exitFunction)114    : m_exitFunction(std::move(exitFunction)) {115  }116 117  ScopeExit(ScopeExit&& other)118    : m_exitFunction(std::move(other.m_exitFunction))119    , m_execute(std::move(other.m_execute)) {120  }121 122  ~ScopeExit() {123    if (m_execute)124      m_exitFunction();125  }126 127  WTF::Function<void()> take() {128    m_execute = false;129    return std::move(m_exitFunction);130  }131 132  void release() { m_execute = false; }133 134  ScopeExit(const ScopeExit&) = delete;135  ScopeExit& operator=(const ScopeExit&) = delete;136  ScopeExit& operator=(ScopeExit&&) = delete;137 138private:139  WTF::Function<void()> m_exitFunction;140  bool m_execute { true };141};142 143template<typename ExitFunction> ScopeExit makeScopeExit(ExitFunction&&);144template<typename ExitFunction>145ScopeExit makeScopeExit(ExitFunction&& exitFunction)146{147    return ScopeExit(std::move(exitFunction));148}149 150// Visitor adapted from http://stackoverflow.com/questions/25338795/is-there-a-name-for-this-tuple-creation-idiom151 152template<class A, class... B> struct Visitor : Visitor<A>, Visitor<B...> {153    Visitor(A a, B... b)154        : Visitor<A>(a)155        , Visitor<B...>(b...)156    {157    }158 159    using Visitor<A>::operator ();160    using Visitor<B...>::operator ();161};162  163template<class A> struct Visitor<A> : A {164    Visitor(A a)165        : A(a)166    {167    }168 169    using A::operator();170};171 172template<class... F> Visitor<F...> makeVisitor(F... f)173{174    return Visitor<F...>(f...);175}176 177void opaqueFunction();178template <typename Visitor, typename... Variants> void visit(Visitor&& v, Variants&&... values)179{180  opaqueFunction();181}182 183} // namespace WTF184 185struct A {186  static void b();187};188 189RefCountable* make_obj();190 191void someFunction();192template <typename Callback> void call(Callback callback) {193  someFunction();194  callback();195}196void callAsync(const WTF::Function<void()>&);197 198void raw_ptr() {199  RefCountable* ref_countable = make_obj();200  auto foo1 = [ref_countable](){201    // expected-warning@-1{{Captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}202    ref_countable->method();203  };204  auto foo2 = [&ref_countable](){205    // expected-warning@-1{{Captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}206    ref_countable->method();207  };208  auto foo3 = [&](){209    ref_countable->method();210    // expected-warning@-1{{Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}211    ref_countable = nullptr;212  };213 214  auto foo4 = [=](){215    ref_countable->method();216    // expected-warning@-1{{Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}217  };218 219  call(foo1);220  call(foo2);221  call(foo3);222  call(foo4);223 224  // Confirm that the checker respects [[clang::suppress]].225  RefCountable* suppressed_ref_countable = nullptr;226  [[clang::suppress]] auto foo5 = [suppressed_ref_countable](){};227  // no warning.228  call(foo5);229}230 231void references() {232  RefCountable automatic;233  RefCountable& ref_countable_ref = automatic;234  auto foo1 = [ref_countable_ref](){ ref_countable_ref.constMethod(); };235  auto foo2 = [&ref_countable_ref](){ ref_countable_ref.method(); };236  // expected-warning@-1{{Captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}237  auto foo3 = [&](){ ref_countable_ref.method(); };238  // expected-warning@-1{{Implicitly captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}239  auto foo4 = [=](){ ref_countable_ref.constMethod(); };240 241  call(foo1);242  call(foo2);243  call(foo3);244  call(foo4);245}246 247void quiet() {248// This code is not expected to trigger any warnings.249  {250    RefCountable automatic;251    RefCountable &ref_countable_ref = automatic;252  }253 254  auto foo3 = [&]() {};255  auto foo4 = [=]() {};256 257  call(foo3);258  call(foo4);259 260  RefCountable *ref_countable = nullptr;261}262 263template <typename Callback>264void map(RefCountable* start, [[clang::noescape]] Callback&& callback)265{266  while (start) {267    callback(*start);268    start = start->next();269  }270}271 272template <typename Callback1, typename Callback2>273void doubleMap(RefCountable* start, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)274{275  while (start) {276    callback1(*start);277    callback2(*start);278    start = start->next();279  }280}281 282void noescape_lambda() {283  RefCountable* someObj = make_obj();284  RefCountable* otherObj = make_obj();285  map(make_obj(), [&](RefCountable& obj) {286    otherObj->method();287  });288  doubleMap(make_obj(), [&](RefCountable& obj) {289    otherObj->method();290  }, [&](RefCountable& obj) {291    otherObj->method();292    // expected-warning@-1{{Implicitly captured raw-pointer 'otherObj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}293  });294  ([&] {295    someObj->method();296  })();297}298 299void lambda_capture_param(RefCountable* obj) {300  auto someLambda = [&]() {301    obj->method();302  };303  someLambda();304  someLambda();305}306 307struct RefCountableWithLambdaCapturingThis {308  void ref() const;309  void deref() const;310  void nonTrivial();311 312  void method_captures_this_safe() {313    auto lambda = [&]() {314      nonTrivial();315    };316    lambda();317  }318 319  void method_captures_this_unsafe() {320    auto lambda = [&]() {321      nonTrivial();322      // expected-warning@-1{{Implicitly captured raw-pointer 'this' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}323    };324    call(lambda);325  }326 327  void method_captures_this_unsafe_capture_local_var_explicitly() {328    RefCountable* x = make_obj();329    call([this, protectedThis = RefPtr { this }, x]() {330      // expected-warning@-1{{Captured raw-pointer 'x' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}331      nonTrivial();332      x->method();333    });334  }335 336  void method_captures_this_with_other_protected_var() {337    RefCountable* x = make_obj();338    call([this, protectedX = RefPtr { x }]() {339      // expected-warning@-1{{Captured raw-pointer 'this' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}340      nonTrivial();341      protectedX->method();342    });343  }344 345  void method_captures_this_unsafe_capture_local_var_explicitly_with_deref() {346    RefCountable* x = make_obj();347    call([this, protectedThis = Ref { *this }, x]() {348      // expected-warning@-1{{Captured raw-pointer 'x' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}349      nonTrivial();350      x->method();351    });352  }353 354  void method_captures_this_unsafe_local_var_via_vardecl() {355    RefCountable* x = make_obj();356    auto lambda = [this, protectedThis = Ref { *this }, x]() {357      // expected-warning@-1{{Captured raw-pointer 'x' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}358      nonTrivial();359      x->method();360    };361    call(lambda);362  }363 364  void method_captures_this_with_guardian() {365    auto lambda = [this, protectedThis = Ref { *this }]() {366      nonTrivial();367    };368    call(lambda);369  }370 371  void method_captures_this_with_guardian_refptr() {372    auto lambda = [this, protectedThis = RefPtr { &*this }]() {373      nonTrivial();374    };375    call(lambda);376  }377 378  void forEach(const WTF::Function<void(RefCountable&)>&);379  void method_captures_this_with_lambda_with_no_escape() {380    auto run = [&]([[clang::noescape]] const WTF::Function<void(RefCountable&)>& func) {381      forEach(func);382    };383    run([&](RefCountable&) {384      nonTrivial();385    });386  }387 388  static void callLambda([[clang::noescape]] const WTF::Function<RefPtr<RefCountable>()>&);389  void method_captures_this_in_template_method() {390    RefCountable* obj = make_obj();391    WTF::HashMap<int, RefPtr<RefCountable>> nextMap;392    nextMap.ensure(3, [&] {393      return obj->next();394    });395    nextMap+[&] {396      return obj->next();397    };398    WTF::HashMap<int, RefPtr<RefCountable>>::ifAny(nextMap, [&](auto& item) -> bool {399      return item->next() && obj->next();400    });401    callLambda([&]() -> RefPtr<RefCountable> {402      return obj->next();403    });404    WTF::HashMap<int, RefPtr<RefCountable>> anotherMap([&] {405      return obj->next();406    });407  }408 409  void callAsyncNoescape([[clang::noescape]] WTF::Function<bool(RefCountable&)>&&);410  void method_temp_lambda(RefCountable* obj) {411    callAsyncNoescape([this, otherObj = RefPtr { obj }](auto& obj) {412      return otherObj == &obj;413    });414  }415 416  void method_nested_lambda() {417    callAsync([this, protectedThis = Ref { *this }] {418      callAsync([this, protectedThis = static_cast<const Ref<RefCountableWithLambdaCapturingThis>&&>(protectedThis)] {419        nonTrivial();420      });421    });422  }423 424  void method_nested_lambda2() {425    callAsync([this, protectedThis = RefPtr { this }] {426      callAsync([this, protectedThis = std::move(*protectedThis)] {427        nonTrivial();428      });429    });430  }431 432  void method_nested_lambda3() {433    callAsync([this, protectedThis = RefPtr { this }] {434      callAsync([this] {435        // expected-warning@-1{{Captured raw-pointer 'this' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}436        nonTrivial();437      });438    });439  }440};441 442struct NonRefCountableWithLambdaCapturingThis {443  void nonTrivial();444 445  void method_captures_this_safe() {446    auto lambda = [&]() {447      nonTrivial();448    };449    lambda();450  }451 452  void method_captures_this_unsafe() {453    auto lambda = [&]() {454      nonTrivial();455    };456    call(lambda);457  }458};459 460void trivial_lambda() {461  RefCountable* ref_countable = make_obj();462  auto trivial_lambda = [&]() {463    return ref_countable->trivial();464  };465  trivial_lambda();466}467 468bool call_lambda_var_decl() {469  RefCountable* ref_countable = make_obj();470  auto lambda1 = [&]() -> bool {471    return ref_countable->next();472  };473  auto lambda2 = [=]() -> bool {474    return ref_countable->next();475  };476  return lambda1() && lambda2();477}478 479void lambda_with_args(RefCountable* obj) {480  auto trivial_lambda = [&](int v) {481    obj->method();482  };483  trivial_lambda(1);484}485 486void callFunctionOpaque(WTF::Function<void()>&&);487void callFunction(WTF::Function<void()>&& function) {488  someFunction();489  function();490}491 492void lambda_converted_to_function(RefCountable* obj)493{494  callFunction([&]() {495    obj->method();496    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}497  });498  callFunctionOpaque([&]() {499    obj->method();500    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}501  });502}503 504void capture_copy_in_lambda(CheckedObj& checked) {505  callFunctionOpaque([checked]() mutable {506    checked.method();507  });508  auto* ptr = &checked;509  callFunctionOpaque([ptr]() mutable {510    // expected-warning@-1{{Captured raw-pointer 'ptr' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}511    ptr->method();512  });513}514 515class Iterator {516public:517  Iterator(void* array, unsigned long sizeOfElement, unsigned int index);518  Iterator(const Iterator&);519  Iterator& operator=(const Iterator&);520  bool operator==(const Iterator&);521 522  Iterator& operator++();523  int& operator*();524 525private:526  void* current { nullptr };527  unsigned long sizeOfElement { 0 };528};529 530void ranges_for_each(RefCountable* obj) {531  int array[] = { 1, 2, 3, 4, 5 };532  std::ranges::for_each(Iterator(array, sizeof(*array), 0), Iterator(array, sizeof(*array), 5), [&](int& item) {533    obj->method();534    ++item;535  });536}537 538class IntCollection {539public:540  int* begin();541  int* end();542  const int* begin() const;543  const int* end() const;544};545 546class RefCountedObj {547public:548  void ref();549  void deref();550 551  bool allOf(const IntCollection&);552  bool isMatch(int);553 554  void call() const;555  void callLambda([[clang::noescape]] const WTF::Function<void ()>& callback) const;556  void doSomeWork() const;557};558 559bool RefCountedObj::allOf(const IntCollection& collection) {560  return std::ranges::all_of(collection, [&](auto& number) {561    return isMatch(number);562  });563}564 565void RefCountedObj::callLambda([[clang::noescape]] const WTF::Function<void ()>& callback) const566{567    callback();568}569 570void RefCountedObj::call() const571{572    auto lambda = [&] {573        doSomeWork();574    };575    callLambda(lambda);576}577 578void scope_exit(RefCountable* obj) {579  auto scope = WTF::makeScopeExit([&] {580    obj->method();581  });582  someFunction();583  WTF::ScopeExit scope2([&] {584    obj->method();585  });586  someFunction();587}588 589void doWhateverWith(WTF::ScopeExit& obj);590 591void scope_exit_with_side_effect(RefCountable* obj) {592  auto scope = WTF::makeScopeExit([&] {593    obj->method();594    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}595  });596  doWhateverWith(scope);597}598 599void scope_exit_static(RefCountable* obj) {600  static auto scope = WTF::makeScopeExit([&] {601    obj->method();602    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}603  });604}605 606WTF::Function<void()> scope_exit_take_lambda(RefCountable* obj) {607  auto scope = WTF::makeScopeExit([&] {608    obj->method();609    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}610  });611  return scope.take();612}613 614// FIXME: Ideally, we treat release() as a trivial function.615void scope_exit_release(RefCountable* obj) {616  auto scope = WTF::makeScopeExit([&] {617    obj->method();618    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}619  });620  scope.release();621}622 623void make_visitor(RefCountable* obj) {624  auto visitor = WTF::makeVisitor([&] {625    obj->method();626  });627}628 629void use_visitor(RefCountable* obj) {630  auto visitor = WTF::makeVisitor([&] {631    obj->method();632  });633  WTF::visit(visitor, obj);634}635 636template <typename Visitor, typename ObjectType>637void bad_visit(Visitor&, ObjectType*) {638  someFunction();639}640 641void static_visitor(RefCountable* obj) {642  static auto visitor = WTF::makeVisitor([&] {643    obj->method();644    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}645  });646}647 648void bad_use_visitor(RefCountable* obj) {649  auto visitor = WTF::makeVisitor([&] {650    obj->method();651    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]}}652  });653  bad_visit(visitor, obj);654}655