brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.0 KiB · 76a1da7 Raw
380 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedLambdaCapturesChecker -verify %s2 3#include "objc-mock-types.h"4 5namespace std {6 7template <typename T>8class unique_ptr {9private:10  T *t;11 12public:13  unique_ptr() : t(nullptr) { }14  unique_ptr(T *t) : t(t) { }15  ~unique_ptr() {16    if (t)17      delete t;18  }19  template <typename U> unique_ptr(unique_ptr<U>&& u)20    : t(u.t)21  {22    u.t = nullptr;23  }24  T *get() const { return t; }25  T *operator->() const { return t; }26  T &operator*() const { return *t; }27  unique_ptr &operator=(T *) { return *this; }28  explicit operator bool() const { return !!t; }29};30 31};32 33namespace WTF {34 35namespace Detail {36 37template<typename Out, typename... In>38class CallableWrapperBase {39public:40    virtual ~CallableWrapperBase() { }41    virtual Out call(In...) = 0;42};43 44template<typename, typename, typename...> class CallableWrapper;45 46template<typename CallableType, typename Out, typename... In>47class CallableWrapper : public CallableWrapperBase<Out, In...> {48public:49    explicit CallableWrapper(CallableType& callable)50        : m_callable(callable) { }51    Out call(In... in) final { return m_callable(in...); }52 53private:54    CallableType m_callable;55};56 57} // namespace Detail58 59template<typename> class Function;60 61template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*);62 63template <typename Out, typename... In>64class Function<Out(In...)> {65public:66    using Impl = Detail::CallableWrapperBase<Out, In...>;67 68    Function() = default;69 70    template<typename FunctionType>71    Function(FunctionType f)72        : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>(f)) { }73 74    Out operator()(In... in) const { return m_callableWrapper->call(in...); }75    explicit operator bool() const { return !!m_callableWrapper; }76 77private:78    enum AdoptTag { Adopt };79    Function(Impl* impl, AdoptTag)80        : m_callableWrapper(impl)81    {82    }83 84    friend Function adopt<Out, In...>(Impl*);85 86    std::unique_ptr<Impl> m_callableWrapper;87};88 89template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl)90{91    return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);92}93 94template <typename KeyType, typename ValueType>95class HashMap {96public:97  HashMap();98  HashMap([[clang::noescape]] const Function<ValueType()>&);99  void ensure(const KeyType&, [[clang::noescape]] const Function<ValueType()>&);100  bool operator+([[clang::noescape]] const Function<ValueType()>&) const;101  static void ifAny(HashMap, [[clang::noescape]] const Function<bool(ValueType)>&);102 103private:104  ValueType* m_table { nullptr };105};106 107} // namespace WTF108 109struct A {110  static void b();111};112 113SomeObj* make_obj();114CFMutableArrayRef make_cf();115dispatch_queue_t make_os();116 117void someFunction();118template <typename Callback> void call(Callback callback) {119  someFunction();120  callback();121}122void callAsync(const WTF::Function<void()>&);123 124void raw_ptr() {125  SomeObj* obj = make_obj();126  auto foo1 = [obj](){127    // expected-warning@-1{{Captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}128    [obj doWork];129  };130  call(foo1);131 132  auto foo2 = [&obj](){133    // expected-warning@-1{{Captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}134    [obj doWork];135  };136  auto foo3 = [&](){137    [obj doWork];138    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}139    obj = nullptr;140  };141  auto foo4 = [=](){142    [obj doWork];143    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}144  };145  146  auto cf = make_cf();147  auto bar1 = [cf](){148    // expected-warning@-1{{Captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}149    CFArrayAppendValue(cf, nullptr);150  };151  auto bar2 = [&cf](){152    // expected-warning@-1{{Captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}153    CFArrayAppendValue(cf, nullptr);154  };155  auto bar3 = [&](){156    CFArrayAppendValue(cf, nullptr);157    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}158    cf = nullptr;159  };160  auto bar4 = [=](){161    CFArrayAppendValue(cf, nullptr);162    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}163  };164 165  auto os = make_os();166  auto baz1 = [os](){167    // expected-warning@-1{{Captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}168    dispatch_queue_get_label(os);169  };170  auto baz2 = [&os](){171    // expected-warning@-1{{Captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}172    dispatch_queue_get_label(os);173  };174  auto baz3 = [&](){175    dispatch_queue_get_label(os);176    // expected-warning@-1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}177    os = nullptr;178  };179  auto baz4 = [=](){180    dispatch_queue_get_label(os);181    // expected-warning@-1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}182  };183 184  call(foo1);185  call(foo2);186  call(foo3);187  call(foo4);188 189  call(bar1);190  call(bar2);191  call(bar3);192  call(bar4);193 194  call(baz1);195  call(baz2);196  call(baz3);197  call(baz4);198 199  // Confirm that the checker respects [[clang::suppress]].200  SomeObj* suppressed_obj = make_obj();201  [[clang::suppress]] auto foo5 = [suppressed_obj](){202    [suppressed_obj doWork];203  };204  // no warning.205  call(foo5);206 207  // Confirm that the checker respects [[clang::suppress]].208  CFMutableArrayRef suppressed_cf = make_cf();209  [[clang::suppress]] auto bar5 = [suppressed_cf](){210    CFArrayAppendValue(suppressed_cf, nullptr);211  };212  // no warning.213  call(bar5);214 215  // Confirm that the checker respects [[clang::suppress]].216  dispatch_queue_t suppressed_os = make_os();217  [[clang::suppress]] auto baz5 = [suppressed_os](){218    dispatch_queue_get_label(suppressed_os);219  };220  // no warning.221  call(baz5);222}223 224void quiet() {225// This code is not expected to trigger any warnings.226  SomeObj *obj;227 228  auto foo3 = [&]() {};229  auto foo4 = [=]() {};230 231  call(foo3);232  call(foo4);233 234  obj = nullptr;235}236 237template <typename Callback>238void map(SomeObj* start, [[clang::noescape]] Callback&& callback)239{240  while (start) {241    callback(start);242    start = [start next];243  }244}245 246template <typename Callback1, typename Callback2>247void doubleMap(SomeObj* start, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)248{249  while (start) {250    callback1(start);251    callback2(start);252    start = [start next];253  }254}255 256template <typename Callback1, typename Callback2>257void get_count_cf(CFArrayRef array, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)258{259  auto count = CFArrayGetCount(array);260  callback1(count);261  callback2(count);262}263 264template <typename Callback1, typename Callback2>265void get_count_os(dispatch_queue_t queue, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)266{267  auto* label = dispatch_queue_get_label(queue);268  callback1(label);269  callback2(label);270}271 272void noescape_lambda() {273  SomeObj* someObj = make_obj();274  SomeObj* otherObj = make_obj();275  map(make_obj(), [&](SomeObj *obj) {276    [otherObj doWork];277  });278  doubleMap(make_obj(), [&](SomeObj *obj) {279    [otherObj doWork];280  }, [&](SomeObj *obj) {281    [otherObj doWork];282    // expected-warning@-1{{Implicitly captured raw-pointer 'otherObj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}283  });284  ([&] {285    [someObj doWork];286  })();287 288  CFMutableArrayRef someCF = make_cf();289  get_count_cf(make_cf(), [&](CFIndex count) {290    CFArrayAppendValue(someCF, nullptr);291  }, [&](CFIndex count) {292    CFArrayAppendValue(someCF, nullptr);293    // expected-warning@-1{{Implicitly captured reference 'someCF' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}294  });295 296  dispatch_queue_t someOS = make_os();297  get_count_os(make_os(), [&](const char* label) {298    dispatch_queue_get_label(someOS);299  }, [&](const char* label) {300    dispatch_queue_get_label(someOS);301    // expected-warning@-1{{Implicitly captured reference 'someOS' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}302  });303}304 305void callFunctionOpaque(WTF::Function<void()>&&);306void callFunction(WTF::Function<void()>&& function) {307  someFunction();308  function();309}310 311void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf, dispatch_queue_t os)312{313  callFunction([&]() {314    [obj doWork];315    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}316    CFArrayAppendValue(cf, nullptr);317    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}318    dispatch_queue_get_label(os);319    // expected-warning@-1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}320  });321  callFunctionOpaque([&]() {322    [obj doWork];323    // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}324    CFArrayAppendValue(cf, nullptr);325    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}326    dispatch_queue_get_label(os);327    // expected-warning@-1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}328  });329}330 331@interface ObjWithSelf : NSObject {332  RetainPtr<id> delegate;333  OSObjectPtr<dispatch_queue_t> queue;334}335-(void)doWork;336-(void)doMoreWork;337-(void)run;338@end339 340@implementation ObjWithSelf341-(void)doWork {342  auto doWork = [&] {343    // expected-warning@-1{{Implicitly captured raw-pointer 'self' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}344    someFunction();345    [delegate doWork];346  };347  auto doMoreWork = [=] {348    // expected-warning@-1{{Implicitly captured raw-pointer 'self' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}349    someFunction();350    [delegate doWork];351  };352  auto doExtraWork = [&, protectedSelf = retainPtr(self)] {353    someFunction();354    [delegate doWork];355  };356  auto* queuePtr = queue.get();357  auto doAdditionalWork = [&] {358    someFunction();359    dispatch_queue_get_label(queuePtr);360    // expected-warning@-1{{Implicitly captured raw-pointer 'queuePtr' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}361  };362  callFunctionOpaque(doWork);363  callFunctionOpaque(doMoreWork);364  callFunctionOpaque(doExtraWork);365  callFunctionOpaque(doAdditionalWork);366}367 368-(void)doMoreWork {369  auto doWork = [self, protectedSelf = retainPtr(self)] {370    someFunction();371    [self doWork];372  };373  callFunctionOpaque(doWork);374}375 376-(void)run {377  someFunction();378}379@end380