Skip to content

Commit f4f2220

Browse files
committed
Merge #19132: qt: lock cs_main, m_cached_tip_mutex in that order
f46b678 qt: lock cs_main, m_cached_tip_mutex in that order (Vasil Dimov) Pull request description: Always lock the mutexes `cs_main` and `m_cached_tip_mutex` in the same order: `cs_main`, `m_cached_tip_mutex`. Otherwise we may end up in a deadlock. `ClientModel::m_cached_tip_blocks` is protected by `ClientModel::m_cached_tip_mutex`. There are two access paths that lock the two mutexes in opposite order: ``` validation.cpp:2868 CChainState::ActivateBestChain(): lock cs_main validation.cpp:2916 CChainState::ActivateBestChain(): call uiInterface.NotifyBlockTip() ui_interface.cpp:52 CClientUIInterface::NotifyBlockTip(): go deep in boost ... qt/clientmodel.cpp:255 BlockTipChanged(): lock m_cached_tip_mutex ``` and ``` qt/clientmodel.cpp:119 ClientModel::getBestBlockHash(): lock m_cached_tip_mutex qt/clientmodel.cpp:121 ClientModel::getBestBlockHash(): call m_node.getBestBlockHash() interfaces/node.cpp:200 NodeImpl::getBestBlockHash(): lock cs_main ``` From `debug.log`: ``` POTENTIAL DEADLOCK DETECTED Previous lock order was: m_cs_chainstate validation.cpp:2851 (1) cs_main validation.cpp:2868 ::mempool.cs validation.cpp:2868 (2) clientmodel->m_cached_tip_mutex qt/clientmodel.cpp:255 Current lock order is: (2) m_cached_tip_mutex qt/clientmodel.cpp:119 (1) ::cs_main interfaces/node.cpp:200 ``` The possible deadlock was introduced in #17993 ACKs for top commit: jonasschnelli: Tested ACK f46b678 Tree-SHA512: 904f24b39bdc97c4d0ecb897a6980d8d479814535eb167e23105238800ea2f1f85273e3370cf894db58bc597f94c4f2e81fb68d0ff3362d468c16af5ce8f5d78
2 parents 7f9800c + f46b678 commit f4f2220

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

src/qt/clientmodel.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,23 @@ int ClientModel::getNumBlocks() const
116116

117117
uint256 ClientModel::getBestBlockHash()
118118
{
119+
uint256 tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
120+
121+
if (!tip.IsNull()) {
122+
return tip;
123+
}
124+
125+
// Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
126+
// The following will lock `cs_main` (and release it), so we must not
127+
// own `m_cached_tip_mutex` here.
128+
tip = m_node.getBestBlockHash();
129+
119130
LOCK(m_cached_tip_mutex);
131+
// We checked that `m_cached_tip_blocks` is not null above, but then we
132+
// released the mutex `m_cached_tip_mutex`, so it could have changed in the
133+
// meantime. Thus, check again.
120134
if (m_cached_tip_blocks.IsNull()) {
121-
m_cached_tip_blocks = m_node.getBestBlockHash();
135+
m_cached_tip_blocks = tip;
122136
}
123137
return m_cached_tip_blocks;
124138
}

0 commit comments

Comments
 (0)