CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
243 lines
6.4 KiB
C++
243 lines
6.4 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s
|
|
|
|
#include "mock-types.h"
|
|
|
|
namespace Detail {
|
|
|
|
template<typename Out, typename... In>
|
|
class CallableWrapperBase {
|
|
public:
|
|
virtual ~CallableWrapperBase() { }
|
|
virtual Out call(In...) = 0;
|
|
};
|
|
|
|
template<typename, typename, typename...> class CallableWrapper;
|
|
|
|
template<typename CallableType, typename Out, typename... In>
|
|
class CallableWrapper : public CallableWrapperBase<Out, In...> {
|
|
public:
|
|
explicit CallableWrapper(CallableType&& callable)
|
|
: m_callable(WTFMove(callable)) { }
|
|
CallableWrapper(const CallableWrapper&) = delete;
|
|
CallableWrapper& operator=(const CallableWrapper&) = delete;
|
|
Out call(In... in) final;
|
|
private:
|
|
CallableType m_callable;
|
|
};
|
|
|
|
} // namespace Detail
|
|
|
|
template<typename> class Function;
|
|
|
|
template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*);
|
|
|
|
template <typename Out, typename... In>
|
|
class Function<Out(In...)> {
|
|
public:
|
|
using Impl = Detail::CallableWrapperBase<Out, In...>;
|
|
|
|
Function() = default;
|
|
|
|
template<typename FunctionType>
|
|
Function(FunctionType f);
|
|
|
|
Out operator()(In... in) const;
|
|
explicit operator bool() const { return !!m_callableWrapper; }
|
|
|
|
private:
|
|
enum AdoptTag { Adopt };
|
|
Function(Impl* impl, AdoptTag)
|
|
: m_callableWrapper(impl)
|
|
{
|
|
}
|
|
|
|
friend Function adopt<Out, In...>(Impl*);
|
|
|
|
Impl* m_callableWrapper;
|
|
};
|
|
|
|
template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl)
|
|
{
|
|
return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);
|
|
}
|
|
|
|
enum class DestructionThread : unsigned char { Any, Main, MainRunLoop };
|
|
void ensureOnMainThread(Function<void()>&&); // Sync if called on main thread, async otherwise.
|
|
void ensureOnMainRunLoop(Function<void()>&&); // Sync if called on main run loop, async otherwise.
|
|
|
|
class ThreadSafeRefCountedBase {
|
|
public:
|
|
ThreadSafeRefCountedBase() = default;
|
|
|
|
void ref() const
|
|
{
|
|
++m_refCount;
|
|
}
|
|
|
|
bool hasOneRef() const
|
|
{
|
|
return refCount() == 1;
|
|
}
|
|
|
|
unsigned refCount() const
|
|
{
|
|
return m_refCount;
|
|
}
|
|
|
|
protected:
|
|
bool derefBase() const
|
|
{
|
|
if (!--m_refCount) {
|
|
m_refCount = 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
mutable unsigned m_refCount { 1 };
|
|
};
|
|
|
|
template<class T, DestructionThread destructionThread = DestructionThread::Any> class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {
|
|
public:
|
|
void deref() const
|
|
{
|
|
if (!derefBase())
|
|
return;
|
|
|
|
if constexpr (destructionThread == DestructionThread::Any) {
|
|
delete static_cast<const T*>(this);
|
|
} else if constexpr (destructionThread == DestructionThread::Main) {
|
|
ensureOnMainThread([this] {
|
|
delete static_cast<const T*>(this);
|
|
});
|
|
} else if constexpr (destructionThread == DestructionThread::MainRunLoop) {
|
|
auto deleteThis = [this] {
|
|
delete static_cast<const T*>(this);
|
|
};
|
|
ensureOnMainThread(deleteThis);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
ThreadSafeRefCounted() = default;
|
|
};
|
|
|
|
class FancyRefCountedClass final : public ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main> {
|
|
public:
|
|
static Ref<FancyRefCountedClass> create()
|
|
{
|
|
return adoptRef(*new FancyRefCountedClass());
|
|
}
|
|
|
|
virtual ~FancyRefCountedClass();
|
|
|
|
private:
|
|
FancyRefCountedClass();
|
|
};
|
|
|
|
template<class T, DestructionThread destructionThread = DestructionThread::Any> class BadThreadSafeRefCounted : public ThreadSafeRefCountedBase {
|
|
public:
|
|
void deref() const
|
|
{
|
|
if (!derefBase())
|
|
return;
|
|
|
|
[this] {
|
|
delete static_cast<const T*>(this);
|
|
};
|
|
}
|
|
|
|
protected:
|
|
BadThreadSafeRefCounted() = default;
|
|
};
|
|
|
|
class FancyRefCountedClass2 final : public ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main> {
|
|
// expected-warning@-1{{Class 'ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main>' is used as a base of class 'FancyRefCountedClass2' but doesn't have virtual destructor}}
|
|
public:
|
|
static Ref<FancyRefCountedClass2> create()
|
|
{
|
|
return adoptRef(*new FancyRefCountedClass2());
|
|
}
|
|
|
|
virtual ~FancyRefCountedClass2();
|
|
|
|
private:
|
|
FancyRefCountedClass2();
|
|
};
|
|
|
|
template<class T, DestructionThread destructionThread = DestructionThread::Any> class NestedThreadSafeRefCounted : public ThreadSafeRefCountedBase {
|
|
public:
|
|
void deref() const
|
|
{
|
|
if (!derefBase())
|
|
return;
|
|
ensureOnMainRunLoop([&] {
|
|
auto destroyThis = [&] {
|
|
delete static_cast<const T*>(this);
|
|
};
|
|
destroyThis();
|
|
});
|
|
}
|
|
|
|
protected:
|
|
NestedThreadSafeRefCounted() = default;
|
|
};
|
|
|
|
class FancyRefCountedClass3 final : public NestedThreadSafeRefCounted<FancyRefCountedClass3, DestructionThread::Main> {
|
|
public:
|
|
static Ref<FancyRefCountedClass3> create()
|
|
{
|
|
return adoptRef(*new FancyRefCountedClass3());
|
|
}
|
|
|
|
virtual ~FancyRefCountedClass3();
|
|
|
|
private:
|
|
FancyRefCountedClass3();
|
|
};
|
|
|
|
template<class T, DestructionThread destructionThread = DestructionThread::Any> class BadNestedThreadSafeRefCounted : public ThreadSafeRefCountedBase {
|
|
public:
|
|
void deref() const
|
|
{
|
|
if (!derefBase())
|
|
return;
|
|
ensureOnMainThread([&] {
|
|
auto destroyThis = [&] {
|
|
delete static_cast<const T*>(this);
|
|
};
|
|
});
|
|
}
|
|
|
|
protected:
|
|
BadNestedThreadSafeRefCounted() = default;
|
|
};
|
|
|
|
class FancyRefCountedClass4 final : public BadNestedThreadSafeRefCounted<FancyRefCountedClass4, DestructionThread::Main> {
|
|
// expected-warning@-1{{Class 'BadNestedThreadSafeRefCounted<FancyRefCountedClass4, DestructionThread::Main>' is used as a base of class 'FancyRefCountedClass4' but doesn't have virtual destructor}}
|
|
public:
|
|
static Ref<FancyRefCountedClass4> create()
|
|
{
|
|
return adoptRef(*new FancyRefCountedClass4());
|
|
}
|
|
|
|
virtual ~FancyRefCountedClass4();
|
|
|
|
private:
|
|
FancyRefCountedClass4();
|
|
};
|
|
|
|
class FancyRefCountedClass5 final : public ThreadSafeRefCounted<FancyRefCountedClass5, DestructionThread::MainRunLoop> {
|
|
public:
|
|
static Ref<FancyRefCountedClass5> create()
|
|
{
|
|
return adoptRef(*new FancyRefCountedClass5());
|
|
}
|
|
|
|
virtual ~FancyRefCountedClass5();
|
|
|
|
private:
|
|
FancyRefCountedClass5();
|
|
};
|