From ae845aaa398371198f74ea8ea4275dbdc98d3667 Mon Sep 17 00:00:00 2001 From: xxfeng_hw Date: Sat, 29 Jan 2022 14:22:32 +0800 Subject: [PATCH] bugfix for double free of RefBase objects in multi-threads environment. Signed-off-by: xxfeng_hw Change-Id: I3134dabe15c29b5c5cb18fe1e2590a2816dddf33 --- base/include/refbase.h | 1 + base/src/refbase.cpp | 32 ++++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/base/include/refbase.h b/base/include/refbase.h index 4b2b0d0..5c12a0a 100755 --- a/base/include/refbase.h +++ b/base/include/refbase.h @@ -74,6 +74,7 @@ public: void ExtendObjectLifetime(); private: + friend class RefBase; std::atomic atomicStrong_; std::atomic atomicWeak_; std::atomic atomicRefCount_; diff --git a/base/src/refbase.cpp b/base/src/refbase.cpp index d01f082..e24dfde 100755 --- a/base/src/refbase.cpp +++ b/base/src/refbase.cpp @@ -148,12 +148,16 @@ int RefCounter::DecWeakRefCount(const void*) curCount = atomicWeak_.fetch_sub(1, std::memory_order_release); } - int strongRefCount = GetStrongRefCount(); - if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) { - if (callback_) { - callback_(); + if (curCount == 1) { + if (IsLifeTimeExtended()) { + if (callback_) { + callback_(); + } + } else { + DecRefCount(); } } + return curCount; } @@ -299,9 +303,12 @@ RefBase::~RefBase() { if (refs_ != nullptr) { refs_->RemoveCallback(); - refs_->DecRefCount(); - refs_ = nullptr; + if (refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) { + refs_->DecRefCount(); + } } + + refs_ = nullptr; } void RefBase::ExtendObjectLifetime() @@ -333,11 +340,20 @@ void RefBase::DecStrongRef(const void *objectId) return; } - const int curCount = refs_->DecStrongRefCount(objectId); + RefCounter* refs = refs_; + const int curCount = refs->DecStrongRefCount(objectId); if (curCount == 1) { + std::atomic_thread_fence(std::memory_order_acquire); OnLastStrongRef(objectId); + if (!refs->IsLifeTimeExtended()) { + if (refs->callback_) { + // in this case, RefBase's destructor will not delete refs. + refs->callback_(); + } + } } - DecWeakRef(objectId); + + refs->DecWeakRefCount(objectId); } int RefBase::GetSptrRefCount() -- Gitee