1 // RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s
2
3 struct RefCntblBase {
refRefCntblBase4 void ref() {}
derefRefCntblBase5 void deref() {}
6 };
7
8 template<class T>
9 struct DerivedClassTmpl1 : T { };
10 // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl1<RefCntblBase>' but doesn't have virtual destructor}}
11
12 DerivedClassTmpl1<RefCntblBase> a;
foo(DerivedClassTmpl1<RefCntblBase> & obj)13 void foo(DerivedClassTmpl1<RefCntblBase>& obj) { obj.deref(); }
14
15 template<class T>
16 struct DerivedClassTmpl2 : T { };
17 // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl2<RefCntblBase>' but doesn't have virtual destructor}}
18
foo(T)19 template<class T> int foo(T) { DerivedClassTmpl2<T> f; return 42; }
20 int b = foo(RefCntblBase{});
21
22
23 template<class T>
24 struct DerivedClassTmpl3 : T { };
25 // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl3<RefCntblBase>' but doesn't have virtual destructor}}
26
27 typedef DerivedClassTmpl3<RefCntblBase> Foo;
28 Foo c;
29
30 namespace WTF {
31
32 class RefCountedBase {
33 public:
ref() const34 void ref() const { ++count; }
35
36 protected:
derefBase() const37 bool derefBase() const
38 {
39 return !--count;
40 }
41
42 private:
43 mutable unsigned count;
44 };
45
46 template <typename T>
47 class RefCounted : public RefCountedBase {
48 public:
deref() const49 void deref() const {
50 if (derefBase())
51 delete const_cast<T*>(static_cast<const T*>(this));
52 }
53
54 protected:
RefCounted()55 RefCounted() { }
56 };
57
58 template <typename X, typename T>
59 class ExoticRefCounted : public RefCountedBase {
60 public:
deref() const61 void deref() const {
62 if (derefBase())
63 delete (const_cast<T*>(static_cast<const T*>(this)));
64 }
65 };
66
67 template <typename X, typename T>
68 class BadBase : RefCountedBase {
69 public:
deref() const70 void deref() const {
71 if (derefBase())
72 delete (const_cast<X*>(static_cast<const X*>(this)));
73 }
74 };
75
76 template <typename T>
77 class FancyDeref {
78 public:
ref() const79 void ref() const
80 {
81 ++refCount;
82 }
83
deref() const84 void deref() const
85 {
86 --refCount;
87 if (refCount)
88 return;
89 auto deleteThis = [this] {
90 delete static_cast<const T*>(this);
91 };
92 deleteThis();
93 }
94 private:
95 mutable unsigned refCount { 0 };
96 };
97
98 namespace Detail {
99
100 template<typename Out, typename... In>
101 class CallableWrapperBase {
102 public:
~CallableWrapperBase()103 virtual ~CallableWrapperBase() { }
104 virtual Out call(In...) = 0;
105 };
106
107 template<typename, typename, typename...> class CallableWrapper;
108
109 template<typename CallableType, typename Out, typename... In>
110 class CallableWrapper : public CallableWrapperBase<Out, In...> {
111 public:
CallableWrapper(CallableType && callable)112 explicit CallableWrapper(CallableType&& callable)
113 : m_callable(WTFMove(callable)) { }
114 CallableWrapper(const CallableWrapper&) = delete;
115 CallableWrapper& operator=(const CallableWrapper&) = delete;
call(In...in)116 Out call(In... in) final { return m_callable(in...); }
117 private:
118 CallableType m_callable;
119 };
120
121 } // namespace Detail
122
123 template<typename> class Function;
124
125 template <typename Out, typename... In>
126 class Function<Out(In...)> {
127 public:
128 using Impl = Detail::CallableWrapperBase<Out, In...>;
129
130 Function() = default;
131
132 template<typename CallableType>
Function(CallableType && callable)133 Function(CallableType&& callable)
134 : m_callableWrapper(new Detail::CallableWrapper<CallableType, Out, In...>>(callable)) { }
135
136 template<typename FunctionType>
Function(FunctionType f)137 Function(FunctionType f)
138 : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>>(f)) { }
139
~Function()140 ~Function() {
141 }
142
operator ()(In...in) const143 Out operator()(In... in) const {
144 ASSERT(m_callableWrapper);
145 return m_callableWrapper->call(in...);
146 }
147
operator bool() const148 explicit operator bool() const { return !!m_callableWrapper; }
149
150 private:
151 Impl* m_callableWrapper;
152 };
153
154 void ensureOnMainThread(const Function<void()>&& function);
155
156 enum class DestructionThread { Any, MainThread };
157
158 template <typename T, DestructionThread destructionThread = DestructionThread::Any>
159 class FancyDeref2 {
160 public:
ref() const161 void ref() const
162 {
163 ++refCount;
164 }
165
deref() const166 void deref() const
167 {
168 --refCount;
169 if (refCount)
170 return;
171 const_cast<FancyDeref2<T, destructionThread>*>(this)->destroy();
172 }
173
174 private:
destroy()175 void destroy() {
176 delete static_cast<T*>(this);
177 }
178 mutable unsigned refCount { 0 };
179 };
180
181 template <typename S>
182 class DerivedFancyDeref2 : public FancyDeref2<S> {
183 };
184
185 template <typename T>
186 class BadFancyDeref {
187 public:
ref() const188 void ref() const
189 {
190 ++refCount;
191 }
192
deref() const193 void deref() const
194 {
195 --refCount;
196 if (refCount)
197 return;
198 auto deleteThis = [this] {
199 delete static_cast<const T*>(this);
200 };
201 delete this;
202 }
203 private:
204 mutable unsigned refCount { 0 };
205 };
206
207 template <typename T>
208 class ThreadSafeRefCounted {
209 public:
ref() const210 void ref() const { ++refCount; }
deref() const211 void deref() const {
212 if (!--refCount)
213 delete const_cast<T*>(static_cast<const T*>(this));
214 }
215 private:
216 mutable unsigned refCount { 0 };
217 };
218
219 template <typename T>
220 class ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr {
221 public:
ref() const222 void ref() const { ++refCount; }
deref() const223 void deref() const {
224 if (!--refCount)
225 delete const_cast<T*>(static_cast<const T*>(this));
226 }
227 private:
228 mutable unsigned refCount { 0 };
229 };
230
231 } // namespace WTF
232
233 class DerivedClass4 : public WTF::RefCounted<DerivedClass4> { };
234
235 class DerivedClass4b : public WTF::ExoticRefCounted<int, DerivedClass4b> { };
236
237 class DerivedClass4cSub;
238 class DerivedClass4c : public WTF::BadBase<DerivedClass4cSub, DerivedClass4c> { };
239 // expected-warning@-1{{Class 'WTF::BadBase<DerivedClass4cSub, DerivedClass4c>' is used as a base of class 'DerivedClass4c' but doesn't have virtual destructor}}
240 class DerivedClass4cSub : public DerivedClass4c { };
UseDerivedClass4c(DerivedClass4c & obj)241 void UseDerivedClass4c(DerivedClass4c &obj) { obj.deref(); }
242
243 class DerivedClass4d : public WTF::RefCounted<DerivedClass4d> {
244 public:
~DerivedClass4d()245 virtual ~DerivedClass4d() { }
246 };
247 class DerivedClass4dSub : public DerivedClass4d { };
248
249 class DerivedClass5 : public DerivedClass4 { };
250 // expected-warning@-1{{Class 'DerivedClass4' is used as a base of class 'DerivedClass5' but doesn't have virtual destructor}}
UseDerivedClass5(DerivedClass5 & obj)251 void UseDerivedClass5(DerivedClass5 &obj) { obj.deref(); }
252
253 class DerivedClass6 : public WTF::ThreadSafeRefCounted<DerivedClass6> { };
UseDerivedClass6(DerivedClass6 & obj)254 void UseDerivedClass6(DerivedClass6 &obj) { obj.deref(); }
255
256 class DerivedClass7 : public DerivedClass6 { };
257 // expected-warning@-1{{Class 'DerivedClass6' is used as a base of class 'DerivedClass7' but doesn't have virtual destructor}}
UseDerivedClass7(DerivedClass7 & obj)258 void UseDerivedClass7(DerivedClass7 &obj) { obj.deref(); }
259
260 class DerivedClass8 : public WTF::ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<DerivedClass8> { };
UseDerivedClass8(DerivedClass8 & obj)261 void UseDerivedClass8(DerivedClass8 &obj) { obj.deref(); }
262
263 class DerivedClass9 : public DerivedClass8 { };
264 // expected-warning@-1{{Class 'DerivedClass8' is used as a base of class 'DerivedClass9' but doesn't have virtual destructor}}
UseDerivedClass9(DerivedClass9 & obj)265 void UseDerivedClass9(DerivedClass9 &obj) { obj.deref(); }
266
267 class DerivedClass10 : public WTF::FancyDeref<DerivedClass10> { };
UseDerivedClass10(DerivedClass10 & obj)268 void UseDerivedClass10(DerivedClass10 &obj) { obj.deref(); }
269
270 class DerivedClass10b : public WTF::DerivedFancyDeref2<DerivedClass10b> { };
UseDerivedClass10b(DerivedClass10b & obj)271 void UseDerivedClass10b(DerivedClass10b &obj) { obj.deref(); }
272
273 class DerivedClass10c : public WTF::BadFancyDeref<DerivedClass10c> { };
274 // expected-warning@-1{{Class 'WTF::BadFancyDeref<DerivedClass10c>' is used as a base of class 'DerivedClass10c' but doesn't have virtual destructor}}
UseDerivedClass10c(DerivedClass10c & obj)275 void UseDerivedClass10c(DerivedClass10c &obj) { obj.deref(); }
276
277 class BaseClass1 {
278 public:
ref() const279 void ref() const { ++refCount; }
280 void deref() const;
281 private:
282 enum class Type { Base, Derived } type { Type::Base };
283 mutable unsigned refCount { 0 };
284 };
285
286 class DerivedClass11 : public BaseClass1 { };
287
deref() const288 void BaseClass1::deref() const
289 {
290 --refCount;
291 if (refCount)
292 return;
293 switch (type) {
294 case Type::Base:
295 delete const_cast<BaseClass1*>(this);
296 break;
297 case Type::Derived:
298 delete const_cast<DerivedClass11*>(static_cast<const DerivedClass11*>(this));
299 break;
300 }
301 }
302
UseDerivedClass11(DerivedClass11 & obj)303 void UseDerivedClass11(DerivedClass11& obj) { obj.deref(); }
304
305 class BaseClass2;
306 static void deleteBase2(BaseClass2*);
307
308 class BaseClass2 {
309 public:
ref() const310 void ref() const { ++refCount; }
deref() const311 void deref() const
312 {
313 if (!--refCount)
314 deleteBase2(const_cast<BaseClass2*>(this));
315 }
isDerived()316 virtual bool isDerived() { return false; }
317 private:
318 mutable unsigned refCount { 0 };
319 };
320
321 class DerivedClass12 : public BaseClass2 {
isDerived()322 bool isDerived() final { return true; }
323 };
324
UseDerivedClass11(DerivedClass12 & obj)325 void UseDerivedClass11(DerivedClass12& obj) { obj.deref(); }
326
deleteBase2(BaseClass2 * obj)327 void deleteBase2(BaseClass2* obj) {
328 if (obj->isDerived())
329 delete static_cast<DerivedClass12*>(obj);
330 else
331 delete obj;
332 }
333
334 class BaseClass3 {
335 public:
ref() const336 void ref() const { ++refCount; }
deref() const337 void deref() const
338 {
339 if (!--refCount)
340 const_cast<BaseClass3*>(this)->destory();
341 }
isDerived()342 virtual bool isDerived() { return false; }
343
344 private:
345 void destory();
346
347 mutable unsigned refCount { 0 };
348 };
349
350 class DerivedClass13 : public BaseClass3 {
isDerived()351 bool isDerived() final { return true; }
352 };
353
UseDerivedClass11(DerivedClass13 & obj)354 void UseDerivedClass11(DerivedClass13& obj) { obj.deref(); }
355
destory()356 void BaseClass3::destory() {
357 if (isDerived())
358 delete static_cast<DerivedClass13*>(this);
359 else
360 delete this;
361 }
362
363 class RecursiveBaseClass {
364 public:
ref() const365 void ref() const {
366 if (otherObject)
367 otherObject->ref();
368 else
369 ++refCount;
370 }
deref() const371 void deref() const {
372 if (otherObject)
373 otherObject->deref();
374 else {
375 --refCount;
376 if (refCount)
377 return;
378 delete this;
379 }
380 }
381 private:
382 RecursiveBaseClass* otherObject { nullptr };
383 mutable unsigned refCount { 0 };
384 };
385
386 class RecursiveDerivedClass : public RecursiveBaseClass { };
387 // expected-warning@-1{{Class 'RecursiveBaseClass' is used as a base of class 'RecursiveDerivedClass' but doesn't have virtual destructor}}
388
389 class DerivedClass14 : public WTF::RefCounted<DerivedClass14> {
390 public:
~DerivedClass14()391 virtual ~DerivedClass14() { }
392 };
393
UseDerivedClass14(DerivedClass14 & obj)394 void UseDerivedClass14(DerivedClass14& obj) { obj.deref(); }
395
396 class DerivedClass15 : public DerivedClass14 { };
397
UseDerivedClass15(DerivedClass15 & obj)398 void UseDerivedClass15(DerivedClass15& obj) { obj.deref(); }
399