From 6749faa584720c8e9cf6a1b4b7b1e81e69f2db28 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Thu, 6 Jul 2023 13:22:10 +0300 Subject: [PATCH] Fixed #7626: Segfault when new attachment is done to shutting down database --- src/common/classes/RefCounted.h | 5 ++++ src/common/classes/RefMutex.h | 50 +++++++++++++++++++++++++++++++++ src/jrd/jrd.cpp | 4 +++ 3 files changed, 59 insertions(+) diff --git a/src/common/classes/RefCounted.h b/src/common/classes/RefCounted.h index 3c46ba4a90..0c21ce9008 100644 --- a/src/common/classes/RefCounted.h +++ b/src/common/classes/RefCounted.h @@ -47,6 +47,11 @@ namespace Firebird return refCnt; } + void assertNonZero() + { + fb_assert(m_refCnt.value() > 0); + } + protected: RefCounted() : m_refCnt(0) {} diff --git a/src/common/classes/RefMutex.h b/src/common/classes/RefMutex.h index 1d50ae29bc..bb3a938a47 100644 --- a/src/common/classes/RefMutex.h +++ b/src/common/classes/RefMutex.h @@ -158,6 +158,56 @@ namespace Firebird typedef EnsureUnlock MutexEnsureUnlock; typedef EnsureUnlock RefMutexEnsureUnlock; + + // Holds mutex lock and reference to data structure, containing that mutex. + // Lock is never taken in ctor, explicit call 'lock()' is needed later. + + class LateRefGuard + { + public: + LateRefGuard(const char* aReason) + : m_lock(nullptr), m_ref(nullptr), m_from(aReason) + { } + + void lock(Mutex* aLock, RefCounted* aRef) + { + fb_assert(aLock); + fb_assert(!m_lock); + m_lock = aLock; + fb_assert(aRef); + fb_assert(!m_ref); + m_ref = aRef; + + m_lock->enter(m_from); + m_ref->assertNonZero(); + m_ref->addRef(); + } + + ~LateRefGuard() + { + try + { + if (m_lock) + m_lock->leave(); + if (m_ref) + m_ref->release(); + } + catch (const Exception&) + { + DtorException::devHalt(); + } + } + + private: + // Forbid copying + LateRefGuard(const LateRefGuard&); + LateRefGuard& operator=(const LateRefGuard&); + + Mutex* m_lock; + RefCounted* m_ref; + const char* m_from; + }; + } // namespace #endif // CLASSES_REF_MUTEX_H diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 16279d6d0a..4d9cfc7f75 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1644,6 +1644,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch PathName org_filename, expanded_name; bool is_alias = false; MutexEnsureUnlock guardDbInit(dbInitMutex, FB_FUNCTION); + LateRefGuard lateBlocking(FB_FUNCTION); Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, cryptCallback); try @@ -1757,6 +1758,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch } EngineContextHolder tdbb(user_status, jAtt, FB_FUNCTION, AttachmentHolder::ATT_DONT_LOCK); + lateBlocking.lock(jAtt->getStable()->getBlockingMutex(), jAtt->getStable()); attachment->att_crypt_callback = getDefCryptCallback(cryptCallback); attachment->att_client_charset = attachment->att_charset = options.dpb_interp; @@ -2789,6 +2791,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch bool is_alias = false; Firebird::RefPtr config; Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, cryptCallback); + LateRefGuard lateBlocking(FB_FUNCTION); try { @@ -2903,6 +2906,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch dbbGuard.lock(SYNC_EXCLUSIVE); EngineContextHolder tdbb(user_status, jAtt, FB_FUNCTION, AttachmentHolder::ATT_DONT_LOCK); + lateBlocking.lock(jAtt->getStable()->getBlockingMutex(), jAtt->getStable()); attachment->att_crypt_callback = getDefCryptCallback(cryptCallback);