// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s struct RefCntblBase { void ref() {} void deref() {} }; template struct DerivedClassTmpl1 : T { }; // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl1' but doesn't have virtual destructor}} DerivedClassTmpl1 a; void foo(DerivedClassTmpl1& obj) { obj.deref(); } template struct DerivedClassTmpl2 : T { }; // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl2' but doesn't have virtual destructor}} template int foo(T) { DerivedClassTmpl2 f; return 42; } int b = foo(RefCntblBase{}); template struct DerivedClassTmpl3 : T { }; // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl3' but doesn't have virtual destructor}} typedef DerivedClassTmpl3 Foo; Foo c; namespace WTF { class RefCountedBase { public: void ref() const { ++count; } protected: bool derefBase() const { return !--count; } private: mutable unsigned count; }; template class RefCounted : public RefCountedBase { public: void deref() const { if (derefBase()) delete const_cast(static_cast(this)); } protected: RefCounted() { } }; template class ExoticRefCounted : public RefCountedBase { public: void deref() const { if (derefBase()) delete (const_cast(static_cast(this))); } }; template class BadBase : RefCountedBase { public: void deref() const { if (derefBase()) delete (const_cast(static_cast(this))); } }; template class FancyDeref { public: void ref() const { ++refCount; } void deref() const { --refCount; if (refCount) return; auto deleteThis = [this] { delete static_cast(this); }; deleteThis(); } private: mutable unsigned refCount { 0 }; }; namespace Detail { template class CallableWrapperBase { public: virtual ~CallableWrapperBase() { } virtual Out call(In...) = 0; }; template class CallableWrapper; template class CallableWrapper : public CallableWrapperBase { public: explicit CallableWrapper(CallableType&& callable) : m_callable(WTFMove(callable)) { } CallableWrapper(const CallableWrapper&) = delete; CallableWrapper& operator=(const CallableWrapper&) = delete; Out call(In... in) final { return m_callable(in...); } private: CallableType m_callable; }; } // namespace Detail template class Function; template class Function { public: using Impl = Detail::CallableWrapperBase; Function() = default; template Function(CallableType&& callable) : m_callableWrapper(new Detail::CallableWrapper>(callable)) { } template Function(FunctionType f) : m_callableWrapper(new Detail::CallableWrapper>(f)) { } ~Function() { } Out operator()(In... in) const { ASSERT(m_callableWrapper); return m_callableWrapper->call(in...); } explicit operator bool() const { return !!m_callableWrapper; } private: Impl* m_callableWrapper; }; void ensureOnMainThread(const Function&& function); enum class DestructionThread { Any, MainThread }; template class FancyDeref2 { public: void ref() const { ++refCount; } void deref() const { --refCount; if (refCount) return; const_cast*>(this)->destroy(); } private: void destroy() { delete static_cast(this); } mutable unsigned refCount { 0 }; }; template class DerivedFancyDeref2 : public FancyDeref2 { }; template class BadFancyDeref { public: void ref() const { ++refCount; } void deref() const { --refCount; if (refCount) return; auto deleteThis = [this] { delete static_cast(this); }; delete this; } private: mutable unsigned refCount { 0 }; }; template class ThreadSafeRefCounted { public: void ref() const { ++refCount; } void deref() const { if (!--refCount) delete const_cast(static_cast(this)); } private: mutable unsigned refCount { 0 }; }; template class ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr { public: void ref() const { ++refCount; } void deref() const { if (!--refCount) delete const_cast(static_cast(this)); } private: mutable unsigned refCount { 0 }; }; } // namespace WTF class DerivedClass4 : public WTF::RefCounted { }; class DerivedClass4b : public WTF::ExoticRefCounted { }; class DerivedClass4cSub; class DerivedClass4c : public WTF::BadBase { }; // expected-warning@-1{{Class 'WTF::BadBase' is used as a base of class 'DerivedClass4c' but doesn't have virtual destructor}} class DerivedClass4cSub : public DerivedClass4c { }; void UseDerivedClass4c(DerivedClass4c &obj) { obj.deref(); } class DerivedClass4d : public WTF::RefCounted { public: virtual ~DerivedClass4d() { } }; class DerivedClass4dSub : public DerivedClass4d { }; class DerivedClass5 : public DerivedClass4 { }; // expected-warning@-1{{Class 'DerivedClass4' is used as a base of class 'DerivedClass5' but doesn't have virtual destructor}} void UseDerivedClass5(DerivedClass5 &obj) { obj.deref(); } class DerivedClass6 : public WTF::ThreadSafeRefCounted { }; void UseDerivedClass6(DerivedClass6 &obj) { obj.deref(); } class DerivedClass7 : public DerivedClass6 { }; // expected-warning@-1{{Class 'DerivedClass6' is used as a base of class 'DerivedClass7' but doesn't have virtual destructor}} void UseDerivedClass7(DerivedClass7 &obj) { obj.deref(); } class DerivedClass8 : public WTF::ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr { }; void UseDerivedClass8(DerivedClass8 &obj) { obj.deref(); } class DerivedClass9 : public DerivedClass8 { }; // expected-warning@-1{{Class 'DerivedClass8' is used as a base of class 'DerivedClass9' but doesn't have virtual destructor}} void UseDerivedClass9(DerivedClass9 &obj) { obj.deref(); } class DerivedClass10 : public WTF::FancyDeref { }; void UseDerivedClass10(DerivedClass10 &obj) { obj.deref(); } class DerivedClass10b : public WTF::DerivedFancyDeref2 { }; void UseDerivedClass10b(DerivedClass10b &obj) { obj.deref(); } class DerivedClass10c : public WTF::BadFancyDeref { }; // expected-warning@-1{{Class 'WTF::BadFancyDeref' is used as a base of class 'DerivedClass10c' but doesn't have virtual destructor}} void UseDerivedClass10c(DerivedClass10c &obj) { obj.deref(); } class BaseClass1 { public: void ref() const { ++refCount; } void deref() const; private: enum class Type { Base, Derived } type { Type::Base }; mutable unsigned refCount { 0 }; }; class DerivedClass11 : public BaseClass1 { }; void BaseClass1::deref() const { --refCount; if (refCount) return; switch (type) { case Type::Base: delete const_cast(this); break; case Type::Derived: delete const_cast(static_cast(this)); break; } } void UseDerivedClass11(DerivedClass11& obj) { obj.deref(); } class BaseClass2; static void deleteBase2(BaseClass2*); class BaseClass2 { public: void ref() const { ++refCount; } void deref() const { if (!--refCount) deleteBase2(const_cast(this)); } virtual bool isDerived() { return false; } private: mutable unsigned refCount { 0 }; }; class DerivedClass12 : public BaseClass2 { bool isDerived() final { return true; } }; void UseDerivedClass11(DerivedClass12& obj) { obj.deref(); } void deleteBase2(BaseClass2* obj) { if (obj->isDerived()) delete static_cast(obj); else delete obj; } class BaseClass3 { public: void ref() const { ++refCount; } void deref() const { if (!--refCount) const_cast(this)->destory(); } virtual bool isDerived() { return false; } private: void destory(); mutable unsigned refCount { 0 }; }; class DerivedClass13 : public BaseClass3 { bool isDerived() final { return true; } }; void UseDerivedClass11(DerivedClass13& obj) { obj.deref(); } void BaseClass3::destory() { if (isDerived()) delete static_cast(this); else delete this; } class RecursiveBaseClass { public: void ref() const { if (otherObject) otherObject->ref(); else ++refCount; } void deref() const { if (otherObject) otherObject->deref(); else { --refCount; if (refCount) return; delete this; } } private: RecursiveBaseClass* otherObject { nullptr }; mutable unsigned refCount { 0 }; }; class RecursiveDerivedClass : public RecursiveBaseClass { }; // expected-warning@-1{{Class 'RecursiveBaseClass' is used as a base of class 'RecursiveDerivedClass' but doesn't have virtual destructor}} class DerivedClass14 : public WTF::RefCounted { public: virtual ~DerivedClass14() { } }; void UseDerivedClass14(DerivedClass14& obj) { obj.deref(); } class DerivedClass15 : public DerivedClass14 { }; void UseDerivedClass15(DerivedClass15& obj) { obj.deref(); }