337 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedLambdaCapturesChecker -fobjc-arc -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 [obj doWork];128 };129 auto foo2 = [&obj](){130 [obj doWork];131 };132 auto foo3 = [&](){133 [obj doWork];134 obj = nullptr;135 };136 auto foo4 = [=](){137 [obj doWork];138 };139 140 auto cf = make_cf();141 auto bar1 = [cf](){142 // expected-warning@-1{{Captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}143 CFArrayAppendValue(cf, nullptr);144 };145 auto bar2 = [&cf](){146 // expected-warning@-1{{Captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}147 CFArrayAppendValue(cf, nullptr);148 };149 auto bar3 = [&](){150 CFArrayAppendValue(cf, nullptr);151 // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}152 cf = nullptr;153 };154 auto bar4 = [=](){155 CFArrayAppendValue(cf, nullptr);156 // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}157 };158 159 auto os = make_os();160 auto baz1 = [os](){161 dispatch_queue_get_label(os);162 };163 auto baz2 = [&os](){164 dispatch_queue_get_label(os);165 };166 auto baz3 = [&](){167 dispatch_queue_get_label(os);168 os = nullptr;169 };170 auto baz4 = [=](){171 dispatch_queue_get_label(os);172 };173 174 call(foo1);175 call(foo2);176 call(foo3);177 call(foo4);178 179 call(bar1);180 call(bar2);181 call(bar3);182 call(bar4);183 184 call(baz1);185 call(baz2);186 call(baz3);187 call(baz4);188}189 190void quiet() {191// This code is not expected to trigger any warnings.192 SomeObj *obj;193 194 auto foo3 = [&]() {};195 auto foo4 = [=]() {};196 197 call(foo3);198 call(foo4);199 200 obj = nullptr;201}202 203template <typename Callback>204void map(SomeObj* start, [[clang::noescape]] Callback&& callback)205{206 while (start) {207 callback(start);208 start = [start next];209 }210}211 212template <typename Callback1, typename Callback2>213void doubleMap(SomeObj* start, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)214{215 while (start) {216 callback1(start);217 callback2(start);218 start = [start next];219 }220}221 222template <typename Callback1, typename Callback2>223void get_count_cf(CFArrayRef array, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)224{225 auto count = CFArrayGetCount(array);226 callback1(count);227 callback2(count);228}229 230template <typename Callback1, typename Callback2>231void get_count_os(dispatch_queue_t queue, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)232{233 auto* label = dispatch_queue_get_label(queue);234 callback1(label);235 callback2(label);236}237 238void noescape_lambda() {239 SomeObj* someObj = make_obj();240 SomeObj* otherObj = make_obj();241 map(make_obj(), [&](SomeObj *obj) {242 [otherObj doWork];243 });244 doubleMap(make_obj(), [&](SomeObj *obj) {245 [otherObj doWork];246 }, [&](SomeObj *obj) {247 [otherObj doWork];248 });249 ([&] {250 [someObj doWork];251 })();252 253 CFMutableArrayRef someCF = make_cf();254 get_count_cf(make_cf(), [&](CFIndex count) {255 CFArrayAppendValue(someCF, nullptr);256 }, [&](CFIndex count) {257 CFArrayAppendValue(someCF, nullptr);258 // expected-warning@-1{{Implicitly captured reference 'someCF' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}259 });260 261 dispatch_queue_t someOS = make_os();262 get_count_os(make_os(), [&](const char* label) {263 dispatch_queue_get_label(someOS);264 }, [&](const char* label) {265 dispatch_queue_get_label(someOS);266 });267}268 269void callFunctionOpaque(WTF::Function<void()>&&);270void callFunction(WTF::Function<void()>&& function) {271 someFunction();272 function();273}274 275void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf, dispatch_queue_t os)276{277 callFunction([&]() {278 [obj doWork];279 CFArrayAppendValue(cf, nullptr);280 // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}281 dispatch_queue_get_label(os);282 });283 callFunctionOpaque([&]() {284 [obj doWork];285 CFArrayAppendValue(cf, nullptr);286 // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}287 dispatch_queue_get_label(os);288 });289}290 291@interface ObjWithSelf : NSObject {292 RetainPtr<id> delegate;293 OSObjectPtr<dispatch_queue_t> queue;294}295-(void)doWork;296-(void)doMoreWork;297-(void)run;298@end299 300@implementation ObjWithSelf301-(void)doWork {302 auto doWork = [&] {303 someFunction();304 [delegate doWork];305 };306 auto doMoreWork = [=] {307 someFunction();308 [delegate doWork];309 };310 auto doExtraWork = [&, protectedSelf = retainPtr(self)] {311 someFunction();312 [delegate doWork];313 };314 auto* queuePtr = queue.get();315 auto doAdditionalWork = [&] {316 someFunction();317 dispatch_queue_get_label(queuePtr);318 };319 callFunctionOpaque(doWork);320 callFunctionOpaque(doMoreWork);321 callFunctionOpaque(doExtraWork);322 callFunctionOpaque(doAdditionalWork);323}324 325-(void)doMoreWork {326 auto doWork = [self, protectedSelf = retainPtr(self)] {327 someFunction();328 [self doWork];329 };330 callFunctionOpaque(doWork);331}332 333-(void)run {334 someFunction();335}336@end337