From 8c9b07813d36f5b7ce993017f5a6612455d7c012 Mon Sep 17 00:00:00 2001 From: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:24:53 -0400 Subject: [PATCH] mqb: fix ClientSession::initiateShutdown crash (#349) Signed-off-by: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> --- src/groups/mqb/mqba/mqba_clientsession.cpp | 45 +++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/groups/mqb/mqba/mqba_clientsession.cpp b/src/groups/mqb/mqba/mqba_clientsession.cpp index 6a5024cafe..d6d8d29f59 100644 --- a/src/groups/mqb/mqba/mqba_clientsession.cpp +++ b/src/groups/mqb/mqba/mqba_clientsession.cpp @@ -2816,16 +2816,41 @@ void ClientSession::initiateShutdown(const ShutdownCb& callback, BALL_LOG_INFO << description() << ": initiateShutdown"; - dispatcher()->execute( - bdlf::BindUtil::bind( - bdlf::MemFnUtil::memFn(&ClientSession::initiateShutdownDispatched, - d_self.acquire()), - callback, - timeout), - this, - mqbi::DispatcherEventType::e_DISPATCHER); - // Use 'mqbi::DispatcherEventType::e_DISPATCHER' to avoid (re)enabling - // 'd_flushList' + // The 'd_self.acquire()' return 'shared_ptr' but that does + // not relate to the 'shared_ptr' acquired by + // 'mqbnet::TransportManagerIterator'. The latter is bound to the + // 'initiateShutdown'. The former can be null after 'd_self.invalidate()' + // call. ('invalidate()' waits for all _acquired_ 'shared_ptr' references + // to drop). + // + // We have a choice, either 1) bind the latter to 'initiateShutdown' to + // make sure 'd_self.acquire()' returns not null, or 2) invoke the + // 'callback' earlier if fail to 'acquire()' because of 'invalidate()', or + // 3) bind _acquired_ 'shared_ptr' to 'initiateShutdown'. + // + // Choosing 2), assuming that calling the (completion) callback from a + // thread other than the *CLIENT* dispatcher thread is ok. The + // 'mwcu::OperationChainLink' expects the completion callback from multiple + // sessions anyway. + + bsl::shared_ptr ptr = d_self.acquire(); + + if (!ptr) { + callback(); + } + else { + dispatcher()->execute( + bdlf::BindUtil::bind( + bdlf::MemFnUtil::memFn( + &ClientSession::initiateShutdownDispatched, + d_self.acquire()), + callback, + timeout), + this, + mqbi::DispatcherEventType::e_DISPATCHER); + // Use 'mqbi::DispatcherEventType::e_DISPATCHER' to avoid (re)enabling + // 'd_flushList' + } } void ClientSession::invalidate()