1 // RUN: %clang_analyze_cc1 -analyzer-checker=webkit.UncountedLambdaCapturesChecker -verify %s 2 3 #include "mock-types.h" 4 5 namespace WTF { 6 7 namespace Detail { 8 9 template<typename Out, typename... In> 10 class CallableWrapperBase { 11 public: 12 virtual ~CallableWrapperBase() { } 13 virtual Out call(In...) = 0; 14 }; 15 16 template<typename, typename, typename...> class CallableWrapper; 17 18 template<typename CallableType, typename Out, typename... In> 19 class CallableWrapper : public CallableWrapperBase<Out, In...> { 20 public: 21 explicit CallableWrapper(CallableType& callable) 22 : m_callable(callable) { } 23 Out call(In... in) final { return m_callable(in...); } 24 25 private: 26 CallableType m_callable; 27 }; 28 29 } // namespace Detail 30 31 template<typename> class Function; 32 33 template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*); 34 35 template <typename Out, typename... In> 36 class Function<Out(In...)> { 37 public: 38 using Impl = Detail::CallableWrapperBase<Out, In...>; 39 40 Function() = default; 41 42 template<typename FunctionType> 43 Function(FunctionType f) 44 : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>(f)) { } 45 46 Out operator()(In... in) const { return m_callableWrapper->call(in...); } 47 explicit operator bool() const { return !!m_callableWrapper; } 48 49 private: 50 enum AdoptTag { Adopt }; 51 Function(Impl* impl, AdoptTag) 52 : m_callableWrapper(impl) 53 { 54 } 55 56 friend Function adopt<Out, In...>(Impl*); 57 58 std::unique_ptr<Impl> m_callableWrapper; 59 }; 60 61 template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl) 62 { 63 return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt); 64 } 65 66 } // namespace WTF 67 68 struct A { 69 static void b(); 70 }; 71 72 RefCountable* make_obj(); 73 74 void someFunction(); 75 template <typename Callback> void call(Callback callback) { 76 someFunction(); 77 callback(); 78 } 79 80 void raw_ptr() { 81 RefCountable* ref_countable = make_obj(); 82 auto foo1 = [ref_countable](){ 83 // expected-warning@-1{{Captured raw-pointer 'ref_countable' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 84 ref_countable->method(); 85 }; 86 auto foo2 = [&ref_countable](){ 87 // expected-warning@-1{{Captured raw-pointer 'ref_countable' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 88 ref_countable->method(); 89 }; 90 auto foo3 = [&](){ 91 ref_countable->method(); 92 // expected-warning@-1{{Implicitly captured raw-pointer 'ref_countable' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 93 ref_countable = nullptr; 94 }; 95 96 auto foo4 = [=](){ 97 ref_countable->method(); 98 // expected-warning@-1{{Implicitly captured raw-pointer 'ref_countable' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 99 }; 100 101 call(foo1); 102 call(foo2); 103 call(foo3); 104 call(foo4); 105 106 // Confirm that the checker respects [[clang::suppress]]. 107 RefCountable* suppressed_ref_countable = nullptr; 108 [[clang::suppress]] auto foo5 = [suppressed_ref_countable](){}; 109 // no warning. 110 call(foo5); 111 } 112 113 void references() { 114 RefCountable automatic; 115 RefCountable& ref_countable_ref = automatic; 116 auto foo1 = [ref_countable_ref](){ ref_countable_ref.constMethod(); }; 117 // expected-warning@-1{{Captured reference 'ref_countable_ref' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 118 auto foo2 = [&ref_countable_ref](){ ref_countable_ref.method(); }; 119 // expected-warning@-1{{Captured reference 'ref_countable_ref' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 120 auto foo3 = [&](){ ref_countable_ref.method(); }; 121 // expected-warning@-1{{Implicitly captured reference 'ref_countable_ref' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 122 auto foo4 = [=](){ ref_countable_ref.constMethod(); }; 123 // expected-warning@-1{{Implicitly captured reference 'ref_countable_ref' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 124 125 call(foo1); 126 call(foo2); 127 call(foo3); 128 call(foo4); 129 } 130 131 void quiet() { 132 // This code is not expected to trigger any warnings. 133 { 134 RefCountable automatic; 135 RefCountable &ref_countable_ref = automatic; 136 } 137 138 auto foo3 = [&]() {}; 139 auto foo4 = [=]() {}; 140 141 call(foo3); 142 call(foo4); 143 144 RefCountable *ref_countable = nullptr; 145 } 146 147 template <typename Callback> 148 void map(RefCountable* start, [[clang::noescape]] Callback&& callback) 149 { 150 while (start) { 151 callback(*start); 152 start = start->next(); 153 } 154 } 155 156 template <typename Callback1, typename Callback2> 157 void doubleMap(RefCountable* start, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2) 158 { 159 while (start) { 160 callback1(*start); 161 callback2(*start); 162 start = start->next(); 163 } 164 } 165 166 void noescape_lambda() { 167 RefCountable* someObj = make_obj(); 168 RefCountable* otherObj = make_obj(); 169 map(make_obj(), [&](RefCountable& obj) { 170 otherObj->method(); 171 }); 172 doubleMap(make_obj(), [&](RefCountable& obj) { 173 otherObj->method(); 174 }, [&](RefCountable& obj) { 175 otherObj->method(); 176 // expected-warning@-1{{Implicitly captured raw-pointer 'otherObj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 177 }); 178 ([&] { 179 someObj->method(); 180 })(); 181 } 182 183 void lambda_capture_param(RefCountable* obj) { 184 auto someLambda = [&]() { 185 obj->method(); 186 }; 187 someLambda(); 188 someLambda(); 189 } 190 191 struct RefCountableWithLambdaCapturingThis { 192 void ref() const; 193 void deref() const; 194 void nonTrivial(); 195 196 void method_captures_this_safe() { 197 auto lambda = [&]() { 198 nonTrivial(); 199 }; 200 lambda(); 201 } 202 203 void method_captures_this_unsafe() { 204 auto lambda = [&]() { 205 nonTrivial(); 206 // expected-warning@-1{{Implicitly captured raw-pointer 'this' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 207 }; 208 call(lambda); 209 } 210 211 void method_captures_this_unsafe_capture_local_var_explicitly() { 212 RefCountable* x = make_obj(); 213 call([this, protectedThis = RefPtr { this }, x]() { 214 // expected-warning@-1{{Captured raw-pointer 'x' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 215 nonTrivial(); 216 x->method(); 217 }); 218 } 219 220 void method_captures_this_with_other_protected_var() { 221 RefCountable* x = make_obj(); 222 call([this, protectedX = RefPtr { x }]() { 223 // expected-warning@-1{{Captured raw-pointer 'this' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 224 nonTrivial(); 225 protectedX->method(); 226 }); 227 } 228 229 void method_captures_this_unsafe_capture_local_var_explicitly_with_deref() { 230 RefCountable* x = make_obj(); 231 call([this, protectedThis = Ref { *this }, x]() { 232 // expected-warning@-1{{Captured raw-pointer 'x' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 233 nonTrivial(); 234 x->method(); 235 }); 236 } 237 238 void method_captures_this_unsafe_local_var_via_vardecl() { 239 RefCountable* x = make_obj(); 240 auto lambda = [this, protectedThis = Ref { *this }, x]() { 241 // expected-warning@-1{{Captured raw-pointer 'x' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 242 nonTrivial(); 243 x->method(); 244 }; 245 call(lambda); 246 } 247 248 void method_captures_this_with_guardian() { 249 auto lambda = [this, protectedThis = Ref { *this }]() { 250 nonTrivial(); 251 }; 252 call(lambda); 253 } 254 255 void method_captures_this_with_guardian_refPtr() { 256 auto lambda = [this, protectedThis = RefPtr { &*this }]() { 257 nonTrivial(); 258 }; 259 call(lambda); 260 } 261 262 }; 263 264 struct NonRefCountableWithLambdaCapturingThis { 265 void nonTrivial(); 266 267 void method_captures_this_safe() { 268 auto lambda = [&]() { 269 nonTrivial(); 270 }; 271 lambda(); 272 } 273 274 void method_captures_this_unsafe() { 275 auto lambda = [&]() { 276 nonTrivial(); 277 }; 278 call(lambda); 279 } 280 }; 281 282 void trivial_lambda() { 283 RefCountable* ref_countable = make_obj(); 284 auto trivial_lambda = [&]() { 285 return ref_countable->trivial(); 286 }; 287 trivial_lambda(); 288 } 289 290 void lambda_with_args(RefCountable* obj) { 291 auto trivial_lambda = [&](int v) { 292 obj->method(); 293 }; 294 trivial_lambda(1); 295 } 296 297 void callFunctionOpaque(WTF::Function<void()>&&); 298 void callFunction(WTF::Function<void()>&& function) { 299 someFunction(); 300 function(); 301 } 302 303 void lambda_converted_to_function(RefCountable* obj) 304 { 305 callFunction([&]() { 306 obj->method(); 307 // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 308 }); 309 callFunctionOpaque([&]() { 310 obj->method(); 311 // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} 312 }); 313 } 314