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