1 // RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s 2 3 #include "mock-types.h" 4 5 namespace Detail { 6 7 template<typename Out, typename... In> 8 class CallableWrapperBase { 9 public: 10 virtual ~CallableWrapperBase() { } 11 virtual Out call(In...) = 0; 12 }; 13 14 template<typename, typename, typename...> class CallableWrapper; 15 16 template<typename CallableType, typename Out, typename... In> 17 class CallableWrapper : public CallableWrapperBase<Out, In...> { 18 public: 19 explicit CallableWrapper(CallableType&& callable) 20 : m_callable(WTFMove(callable)) { } 21 CallableWrapper(const CallableWrapper&) = delete; 22 CallableWrapper& operator=(const CallableWrapper&) = delete; 23 Out call(In... in) final; 24 private: 25 CallableType m_callable; 26 }; 27 28 } // namespace Detail 29 30 template<typename> class Function; 31 32 template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*); 33 34 template <typename Out, typename... In> 35 class Function<Out(In...)> { 36 public: 37 using Impl = Detail::CallableWrapperBase<Out, In...>; 38 39 Function() = default; 40 41 template<typename FunctionType> 42 Function(FunctionType f); 43 44 Out operator()(In... in) const; 45 explicit operator bool() const { return !!m_callableWrapper; } 46 47 private: 48 enum AdoptTag { Adopt }; 49 Function(Impl* impl, AdoptTag) 50 : m_callableWrapper(impl) 51 { 52 } 53 54 friend Function adopt<Out, In...>(Impl*); 55 56 Impl* m_callableWrapper; 57 }; 58 59 template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl) 60 { 61 return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt); 62 } 63 64 enum class DestructionThread : unsigned char { Any, Main, MainRunLoop }; 65 void ensureOnMainThread(Function<void()>&&); // Sync if called on main thread, async otherwise. 66 void ensureOnMainRunLoop(Function<void()>&&); // Sync if called on main run loop, async otherwise. 67 68 class ThreadSafeRefCountedBase { 69 public: 70 ThreadSafeRefCountedBase() = default; 71 72 void ref() const 73 { 74 ++m_refCount; 75 } 76 77 bool hasOneRef() const 78 { 79 return refCount() == 1; 80 } 81 82 unsigned refCount() const 83 { 84 return m_refCount; 85 } 86 87 protected: 88 bool derefBase() const 89 { 90 if (!--m_refCount) { 91 m_refCount = 1; 92 return true; 93 } 94 return false; 95 } 96 97 private: 98 mutable unsigned m_refCount { 1 }; 99 }; 100 101 template<class T, DestructionThread destructionThread = DestructionThread::Any> class ThreadSafeRefCounted : public ThreadSafeRefCountedBase { 102 public: 103 void deref() const 104 { 105 if (!derefBase()) 106 return; 107 108 if constexpr (destructionThread == DestructionThread::Any) { 109 delete static_cast<const T*>(this); 110 } else if constexpr (destructionThread == DestructionThread::Main) { 111 ensureOnMainThread([this] { 112 delete static_cast<const T*>(this); 113 }); 114 } else if constexpr (destructionThread == DestructionThread::MainRunLoop) { 115 auto deleteThis = [this] { 116 delete static_cast<const T*>(this); 117 }; 118 ensureOnMainThread(deleteThis); 119 } 120 } 121 122 protected: 123 ThreadSafeRefCounted() = default; 124 }; 125 126 class FancyRefCountedClass final : public ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main> { 127 public: 128 static Ref<FancyRefCountedClass> create() 129 { 130 return adoptRef(*new FancyRefCountedClass()); 131 } 132 133 virtual ~FancyRefCountedClass(); 134 135 private: 136 FancyRefCountedClass(); 137 }; 138 139 template<class T, DestructionThread destructionThread = DestructionThread::Any> class BadThreadSafeRefCounted : public ThreadSafeRefCountedBase { 140 public: 141 void deref() const 142 { 143 if (!derefBase()) 144 return; 145 146 [this] { 147 delete static_cast<const T*>(this); 148 }; 149 } 150 151 protected: 152 BadThreadSafeRefCounted() = default; 153 }; 154 155 class FancyRefCountedClass2 final : public ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main> { 156 // expected-warning@-1{{Class 'ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main>' is used as a base of class 'FancyRefCountedClass2' but doesn't have virtual destructor}} 157 public: 158 static Ref<FancyRefCountedClass2> create() 159 { 160 return adoptRef(*new FancyRefCountedClass2()); 161 } 162 163 virtual ~FancyRefCountedClass2(); 164 165 private: 166 FancyRefCountedClass2(); 167 }; 168 169 template<class T, DestructionThread destructionThread = DestructionThread::Any> class NestedThreadSafeRefCounted : public ThreadSafeRefCountedBase { 170 public: 171 void deref() const 172 { 173 if (!derefBase()) 174 return; 175 ensureOnMainRunLoop([&] { 176 auto destroyThis = [&] { 177 delete static_cast<const T*>(this); 178 }; 179 destroyThis(); 180 }); 181 } 182 183 protected: 184 NestedThreadSafeRefCounted() = default; 185 }; 186 187 class FancyRefCountedClass3 final : public NestedThreadSafeRefCounted<FancyRefCountedClass3, DestructionThread::Main> { 188 public: 189 static Ref<FancyRefCountedClass3> create() 190 { 191 return adoptRef(*new FancyRefCountedClass3()); 192 } 193 194 virtual ~FancyRefCountedClass3(); 195 196 private: 197 FancyRefCountedClass3(); 198 }; 199 200 template<class T, DestructionThread destructionThread = DestructionThread::Any> class BadNestedThreadSafeRefCounted : public ThreadSafeRefCountedBase { 201 public: 202 void deref() const 203 { 204 if (!derefBase()) 205 return; 206 ensureOnMainThread([&] { 207 auto destroyThis = [&] { 208 delete static_cast<const T*>(this); 209 }; 210 }); 211 } 212 213 protected: 214 BadNestedThreadSafeRefCounted() = default; 215 }; 216 217 class FancyRefCountedClass4 final : public BadNestedThreadSafeRefCounted<FancyRefCountedClass4, DestructionThread::Main> { 218 // expected-warning@-1{{Class 'BadNestedThreadSafeRefCounted<FancyRefCountedClass4, DestructionThread::Main>' is used as a base of class 'FancyRefCountedClass4' but doesn't have virtual destructor}} 219 public: 220 static Ref<FancyRefCountedClass4> create() 221 { 222 return adoptRef(*new FancyRefCountedClass4()); 223 } 224 225 virtual ~FancyRefCountedClass4(); 226 227 private: 228 FancyRefCountedClass4(); 229 }; 230 231 class FancyRefCountedClass5 final : public ThreadSafeRefCounted<FancyRefCountedClass5, DestructionThread::MainRunLoop> { 232 public: 233 static Ref<FancyRefCountedClass5> create() 234 { 235 return adoptRef(*new FancyRefCountedClass5()); 236 } 237 238 virtual ~FancyRefCountedClass5(); 239 240 private: 241 FancyRefCountedClass5(); 242 }; 243