net: make CConnman::m_nodes_mutex non-recursive
What changed, and why it matters
This commit changes a single internal lock in Bitcoin Core's networking code from a recursive mutex (one that lets the same thread lock it multiple times safely) to a plain non-recursive mutex. It also adds many compile-time and runtime checks to make sure no code path tries to lock it twice. The change is defensive hardening: it makes the locking rules stricter so that accidental deadlocks or re-entrancy bugs are caught earlier, but it does not by itself fix a known, exploitable vulnerability.
Treat as routine defensive maintenance. Reviewers should verify that all call sites entering the annotated functions do not already hold m_nodes_mutex, and that the new assertions cannot fire under any legitimate execution path. No emergency deployment is warranted based on this commit alone.
Security signals we found
Mutex hardening: recursive mutex replaced with non-recursive mutex
New AssertLockNotHeld annotations added at function entry points
Compile-time thread-safety annotations added (EXCLUSIVE_LOCKS_REQUIRED)
No functional behavior change in P2P protocol logic
No memory safety, cryptographic, or consensus changes visible in diff
Evidence from the diff
The commit converts CConnman::m_nodes_mutex from RecursiveMutex to Mutex and annotates functions with EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) and inserts AssertLockNotHeld(m_nodes_mutex) at entry points. This enforces that m_nodes_mutex is not already held when these functions are called, preventing nested/re-entrant locking patterns. The change is part of the ongoing work in issue #19303 to remove recursive mutexes. It is a refactoring/hardening patch, not a direct fix for an active security bug.
Changed components
src/net.cppsrc/net.hCConnman networking and peer connection managementInspect captured patch +105 / −41
diff --git a/src/net.cpp b/src/net.cpp
index d046c2a2..f8149ef3 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -381,6 +381,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect,
bool use_v2transport,
const std::optional<Proxy>& proxy_override)
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);
@@ -1688,6 +1689,8 @@ std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const
*/
bool CConnman::AttemptToEvictConnection()
{
+ AssertLockNotHeld(m_nodes_mutex);
+
std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
@@ -1736,6 +1739,8 @@ bool CConnman::AttemptToEvictConnection()
}
void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
+ AssertLockNotHeld(m_nodes_mutex);
+
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
auto sock = hListenSocket.sock->Accept((struct sockaddr*)&sockaddr, &len);
@@ -1768,6 +1773,8 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
const CService& addr_bind,
const CService& addr)
{
+ AssertLockNotHeld(m_nodes_mutex);
+
int nInbound = 0;
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
@@ -1875,6 +1882,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type, bool use_v2transport = false)
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
std::optional<int> max_connections;
switch (conn_type) {
@@ -1992,6 +2000,8 @@ void CConnman::DisconnectNodes()
void CConnman::NotifyNumConnectionsChanged()
{
+ AssertLockNotHeld(m_nodes_mutex);
+
size_t nodes_size;
{
LOCK(m_nodes_mutex);
@@ -2096,6 +2106,7 @@ Sock::EventsPerSock CConnman::GenerateWaitSockets(std::span<CNode* const> nodes)
void CConnman::SocketHandler()
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_total_bytes_sent_mutex);
Sock::EventsPerSock events_per_sock;
@@ -2226,6 +2237,8 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
{
+ AssertLockNotHeld(m_nodes_mutex);
+
for (const ListenSocket& listen_socket : vhListenSocket) {
if (m_interrupt_net->interrupted()) {
return;
@@ -2409,6 +2422,7 @@ void CConnman::DumpAddresses()
void CConnman::ProcessAddrFetch()
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
std::string strDest;
{
@@ -2448,6 +2462,8 @@ void CConnman::StartExtraBlockRelayPeers()
// Return the number of outbound connections that are full relay (not blocks only)
int CConnman::GetFullOutboundConnCount() const
{
+ AssertLockNotHeld(m_nodes_mutex);
+
int nRelevant = 0;
{
LOCK(m_nodes_mutex);
@@ -2466,6 +2482,8 @@ int CConnman::GetFullOutboundConnCount() const
// evict some peer that has finished the handshake)
int CConnman::GetExtraFullOutboundCount() const
{
+ AssertLockNotHeld(m_nodes_mutex);
+
int full_outbound_peers = 0;
{
LOCK(m_nodes_mutex);
@@ -2480,6 +2498,8 @@ int CConnman::GetExtraFullOutboundCount() const
int CConnman::GetExtraBlockRelayCount() const
{
+ AssertLockNotHeld(m_nodes_mutex);
+
int block_relay_peers = 0;
{
LOCK(m_nodes_mutex);
@@ -2513,6 +2533,8 @@ bool CConnman::MultipleManualOrFullOutboundConns(Network net) const
bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network)
{
+ AssertLockNotHeld(m_nodes_mutex);
+
std::array<Network, 5> nets{NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS};
std::shuffle(nets.begin(), nets.end(), FastRandomContext());
@@ -2529,8 +2551,10 @@ bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network)
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std::span<const std::string> seed_nodes)
{
- AssertLockNotHeld(m_unused_i2p_sessions_mutex);
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_reconnections_mutex);
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
+
FastRandomContext rng;
// Connect to specific addresses
if (!connect.empty())
@@ -2900,6 +2924,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
{
+ AssertLockNotHeld(m_nodes_mutex);
std::vector<CAddress> ret;
LOCK(m_nodes_mutex);
for (const CNode* pnode : m_nodes) {
@@ -2913,6 +2938,8 @@ std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo(bool include_connected) const
{
+ AssertLockNotHeld(m_nodes_mutex);
+
std::vector<AddedNodeInfo> ret;
std::list<AddedNodeParams> lAddresses(0);
@@ -2973,8 +3000,10 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo(bool include_connected) co
void CConnman::ThreadOpenAddedConnections()
{
- AssertLockNotHeld(m_unused_i2p_sessions_mutex);
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_reconnections_mutex);
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
+
while (true)
{
CountingSemaphoreGrant<> grant(*semAddnode);
@@ -3010,6 +3039,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect,
bool use_v2transport,
const std::optional<Proxy>& proxy_override)
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);
@@ -3129,6 +3159,8 @@ Mutex NetEventsInterface::g_msgproc_mutex;
void CConnman::ThreadMessageHandler()
{
+ AssertLockNotHeld(m_nodes_mutex);
+
LOCK(NetEventsInterface::g_msgproc_mutex);
while (!flagInterruptMsgProc)
@@ -3168,6 +3200,8 @@ void CConnman::ThreadMessageHandler()
void CConnman::ThreadI2PAcceptIncoming()
{
+ AssertLockNotHeld(m_nodes_mutex);
+
static constexpr auto err_wait_begin = 1s;
static constexpr auto err_wait_cap = 5min;
auto err_wait = err_wait_begin;
@@ -3211,6 +3245,7 @@ void CConnman::ThreadI2PAcceptIncoming()
void CConnman::ThreadPrivateBroadcast()
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
size_t addrman_num_bad_addresses{0};
@@ -3640,6 +3675,7 @@ void CConnman::StopThreads()
void CConnman::StopNodes()
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_reconnections_mutex);
if (fAddressesInitialized) {
@@ -3804,6 +3840,8 @@ uint32_t CConnman::GetMappedAS(const CNetAddr& addr) const
void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
{
+ AssertLockNotHeld(m_nodes_mutex);
+
vstats.clear();
LOCK(m_nodes_mutex);
vstats.reserve(m_nodes.size());
@@ -3829,6 +3867,7 @@ bool CConnman::DisconnectNode(std::string_view strNode)
bool CConnman::DisconnectNode(const CSubNet& subnet)
{
+ AssertLockNotHeld(m_nodes_mutex);
bool disconnected = false;
LOCK(m_nodes_mutex);
for (CNode* pnode : m_nodes) {
@@ -3843,6 +3882,7 @@ bool CConnman::DisconnectNode(const CSubNet& subnet)
bool CConnman::DisconnectNode(const CNetAddr& addr)
{
+ AssertLockNotHeld(m_nodes_mutex);
return DisconnectNode(CSubNet(addr));
}
@@ -4125,6 +4165,8 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
{
+ AssertLockNotHeld(m_nodes_mutex);
+
CNode* found = nullptr;
LOCK(m_nodes_mutex);
for (auto&& pnode : m_nodes) {
@@ -4150,6 +4192,7 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CNetAddr& address) const
void CConnman::PerformReconnections()
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_reconnections_mutex);
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
while (true) {
diff --git a/src/net.h b/src/net.h
index 928d518e..d0171c53 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1154,9 +1154,10 @@ public:
bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !m_added_nodes_mutex, !m_addr_fetches_mutex, !mutexMsgProc);
void StopThreads();
- void StopNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex);
- void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex)
+ void StopNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_reconnections_mutex);
+ void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_reconnections_mutex)
{
+ AssertLockNotHeld(m_nodes_mutex);
AssertLockNotHeld(m_reconnections_mutex);
StopThreads();
StopNodes();
@@ -1186,7 +1187,7 @@ public:
ConnectionType conn_type,
bool use_v2transport,
const std::optional<Proxy>& proxy_override = std::nullopt)
- EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
+ EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex);
/// Group of private broadcast related members.
class PrivateBroadcast
@@ -1254,18 +1255,18 @@ public:
friend struct ConnmanTestMsg;
} m_private_broadcast;
- bool CheckIncomingNonce(uint64_t nonce);
+ bool CheckIncomingNonce(uint64_t nonce) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
void ASMapHealthCheck();
// alias for thread safety annotations only, not defined
- RecursiveMutex& GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex);
+ Mutex& GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex);
- bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
+ bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
void PushMessage(CNode* pnode, CSerializedNetMsg&& msg) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
using NodeFn = std::function<void(CNode*)>;
- void ForEachNode(const NodeFn& func)
+ void ForEachNode(const NodeFn& func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
{
LOCK(m_nodes_mutex);
for (auto&& node : m_nodes) {
@@ -1274,7 +1275,7 @@ public:
}
};
- void ForEachNode(const NodeFn& func) const
+ void ForEachNode(const NodeFn& func) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
{
LOCK(m_nodes_mutex);
for (auto&& node : m_nodes) {
@@ -1320,21 +1321,22 @@ public:
void StartExtraBlockRelayPeers();
// Count the number of full-relay peer we have.
- int GetFullOutboundConnCount() const;
+ int GetFullOutboundConnCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
// Return the number of outbound peers we have in excess of our target (eg,
// if we previously called SetTryNewOutboundPeer(true), and have since set
// to false, we may have extra peers that we wish to disconnect). This may
// return a value less than (num_outbound_connections - num_outbound_slots)
// in cases where some outbound connections are not yet fully connected, or
// not yet fully disconnected.
- int GetExtraFullOutboundCount() const;
+ int GetExtraFullOutboundCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
// Count the number of block-relay-only peers we have over our limit.
- int GetExtraBlockRelayCount() const;
+ int GetExtraBlockRelayCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
bool AddNode(const AddedNodeParams& add) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
bool RemoveAddedNode(std::string_view node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
bool AddedNodesContain(const CAddress& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
- std::vector<AddedNodeInfo> GetAddedNodeInfo(bool include_connected) const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
+ std::vector<AddedNodeInfo> GetAddedNodeInfo(bool include_connected) const
+ EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_nodes_mutex);
/**
* Attempts to open a connection. Currently only used from tests.
@@ -1349,16 +1351,17 @@ public:
* - Max total outbound connection capacity filled
* - Max connection capacity for type is filled
*/
- bool AddConnection(const std::string& address, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
+ bool AddConnection(const std::string& address, ConnectionType conn_type, bool use_v2transport)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex);
- size_t GetNodeCount(ConnectionDirection) const;
+ size_t GetNodeCount(ConnectionDirection) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() const;
uint32_t GetMappedAS(const CNetAddr& addr) const;
- void GetNodeStats(std::vector<CNodeStats>& vstats) const;
- bool DisconnectNode(std::string_view node);
- bool DisconnectNode(const CSubNet& subnet);
- bool DisconnectNode(const CNetAddr& addr);
- bool DisconnectNode(NodeId id);
+ void GetNodeStats(std::vector<CNodeStats>& vstats) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
+ bool DisconnectNode(std::string_view node) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
+ bool DisconnectNode(const CSubNet& subnet) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
+ bool DisconnectNode(const CNetAddr& addr) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
+ bool DisconnectNode(NodeId id) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
//! Used to convey which local services we are offering peers during node
//! connection.
@@ -1422,14 +1425,28 @@ private:
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const Options& options);
- void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex);
+ void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex,
+ !m_nodes_mutex,
+ !m_reconnections_mutex,
+ !m_unused_i2p_sessions_mutex);
+
void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
- void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex);
- void ThreadOpenConnections(std::vector<std::string> connect, std::span<const std::string> seed_nodes) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex);
- void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
- void ThreadI2PAcceptIncoming();
- void ThreadPrivateBroadcast() EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
- void AcceptConnection(const ListenSocket& hListenSocket);
+
+ void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex,
+ !m_nodes_mutex,
+ !m_unused_i2p_sessions_mutex);
+
+ void ThreadOpenConnections(std::vector<std::string> connect, std::span<const std::string> seed_nodes)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex,
+ !m_addr_fetches_mutex,
+ !m_nodes_mutex,
+ !m_reconnections_mutex,
+ !m_unused_i2p_sessions_mutex);
+
+ void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc);
+ void ThreadI2PAcceptIncoming() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
+ void ThreadPrivateBroadcast() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex);
+ void AcceptConnection(const ListenSocket& hListenSocket) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
/**
* Create a `CNode` object from a socket that has just been accepted and add the node to
@@ -1442,10 +1459,11 @@ private:
void CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
NetPermissionFlags permission_flags,
const CService& addr_bind,
- const CService& addr);
+ const CService& addr)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
void DisconnectNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex, !m_nodes_mutex);
- void NotifyNumConnectionsChanged();
+ void NotifyNumConnectionsChanged() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
/** Return true if the peer is inactive and should be disconnected. */
bool InactivityCheck(const CNode& node, NodeClock::time_point now) const;
@@ -1459,7 +1477,7 @@ private:
/**
* Check connected and listening sockets for IO readiness and process them accordingly.
*/
- void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc);
+ void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_total_bytes_sent_mutex, !mutexMsgProc);
/**
* Do the read/write for connected sockets that are ready for IO.
@@ -1474,7 +1492,8 @@ private:
* Accept incoming connections, one from each read-ready listening socket.
* @param[in] events_per_sock Sockets that are ready for IO.
*/
- void SocketHandlerListening(const Sock::EventsPerSock& events_per_sock);
+ void SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc, !m_nodes_mutex, !m_reconnections_mutex);
void ThreadDNSAddressSeed() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex);
@@ -1488,7 +1507,7 @@ private:
* @param[in] host String of the form "host[:port]", e.g. "localhost" or "localhost:8333" or "1.2.3.4:8333".
* @return true if connected to `host`.
*/
- bool AlreadyConnectedToHost(std::string_view host) const;
+ bool AlreadyConnectedToHost(std::string_view host) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
/**
* Determine whether we're already connected to a given address:port.
@@ -1497,14 +1516,14 @@ private:
* @param[in] addr_port Address and port to check.
* @return true if connected to addr_port.
*/
- bool AlreadyConnectedToAddressPort(const CService& addr_port) const;
+ bool AlreadyConnectedToAddressPort(const CService& addr_port) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
/**
* Determine whether we're already connected to a given address.
*/
- bool AlreadyConnectedToAddress(const CNetAddr& addr) const;
+ bool AlreadyConnectedToAddress(const CNetAddr& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
- bool AttemptToEvictConnection();
+ bool AttemptToEvictConnection() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
/**
* Open a new P2P connection.
@@ -1522,7 +1541,7 @@ private:
ConnectionType conn_type,
bool use_v2transport,
const std::optional<Proxy>& proxy_override)
- EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
+ EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const;
@@ -1548,7 +1567,7 @@ private:
/**
* Return vector of current BLOCK_RELAY peers.
*/
- std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const;
+ std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
/**
* Search for a "preferred" network, a reachable network to which we
@@ -1560,7 +1579,7 @@ private:
*
* @return bool Whether a preferred network was found.
*/
- bool MaybePickPreferredNetwork(std::optional<Network>& network);
+ bool MaybePickPreferredNetwork(std::optional<Network>& network) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
// Whether the node should be passed out in ForEach* callbacks
static bool NodeFullyConnected(const CNode* pnode);
@@ -1604,7 +1623,7 @@ private:
mutable Mutex m_added_nodes_mutex;
std::vector<CNode*> m_nodes GUARDED_BY(m_nodes_mutex);
std::list<CNode*> m_nodes_disconnected;
- mutable RecursiveMutex m_nodes_mutex;
+ mutable Mutex m_nodes_mutex;
std::atomic<NodeId> nLastNodeId{0};
unsigned int nPrevNodeCount{0};
@@ -1790,7 +1809,8 @@ private:
std::list<ReconnectionInfo> m_reconnections GUARDED_BY(m_reconnections_mutex);
/** Attempt reconnections, if m_reconnections non-empty. */
- void PerformReconnections() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex, !m_unused_i2p_sessions_mutex);
+ void PerformReconnections()
+ EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_reconnections_mutex, !m_unused_i2p_sessions_mutex);
/**
* Cap on the size of `m_unused_i2p_sessions`, to ensure it does not
@@ -1806,6 +1826,7 @@ private:
{
public:
explicit NodesSnapshot(const CConnman& connman, bool shuffle)
+ EXCLUSIVE_LOCKS_REQUIRED(!connman.m_nodes_mutex)
{
{
LOCK(connman.m_nodes_mutex);
Why this scored 23/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.