Skip to content

Commit 55cc73e

Browse files
committed
fix: use shared_ptr for MnList to prevent use-after-free in GUI
The previous implementation used unique_ptr and returned raw pointers from getMasternodeList(), which created a race condition: 1. GUI thread calls getMasternodeList() and gets raw pointer 2. Core thread updates masternode list, destroying old MnListImpl 3. GUI thread tries to use the now-dangling pointer -> CRASH This was especially problematic during reindex when masternode list updates happen frequently (every block). Solution: Change MnListPtr from unique_ptr to shared_ptr. Now when getMasternodeList() returns a shared_ptr copy, the underlying object is kept alive even if the cached version is replaced. This maintains thread-safety without requiring callers to hold locks for extended periods. Fixes EXC_BAD_ACCESS crash in updateMasternodeCount during reindex.
1 parent c887cff commit 55cc73e

File tree

4 files changed

+6
-6
lines changed

4 files changed

+6
-6
lines changed

src/interfaces/node.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class MnList
114114
virtual void setContext(node::NodeContext* context) = 0;
115115
};
116116

117-
using MnListPtr = std::unique_ptr<MnList>;
117+
using MnListPtr = std::shared_ptr<MnList>;
118118

119119
MnListPtr MakeMNList(const CDeterministicMNList& mn_list);
120120

src/node/interfaces.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ class EVOImpl : public EVO
202202
mnList = context().dmnman->GetListForBlock(tip);
203203
}
204204
mnList.setContext(m_context);
205-
return {std::make_unique<MnListImpl>(mnList), tip};
205+
return {std::make_shared<MnListImpl>(mnList), tip};
206206
}
207207
void setContext(NodeContext* context) override
208208
{
@@ -1242,5 +1242,5 @@ class ChainImpl : public Chain
12421242
namespace interfaces {
12431243
std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
12441244
std::unique_ptr<Chain> MakeChain(node::NodeContext& node) { return std::make_unique<node::ChainImpl>(node); }
1245-
MnListPtr MakeMNList(const CDeterministicMNList& mn_list) { return std::make_unique<node::MnListImpl>(mn_list); }
1245+
MnListPtr MakeMNList(const CDeterministicMNList& mn_list) { return std::make_shared<node::MnListImpl>(mn_list); }
12461246
} // namespace interfaces

src/qt/clientmodel.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ void ClientModel::setMasternodeList(interfaces::MnListPtr mnList, const CBlockIn
111111
Q_EMIT masternodeListChanged();
112112
}
113113

114-
std::pair<const interfaces::MnList*, const CBlockIndex*> ClientModel::getMasternodeList() const
114+
std::pair<interfaces::MnListPtr, const CBlockIndex*> ClientModel::getMasternodeList() const
115115
{
116116
LOCK(cs_mnlist);
117-
return {Assert(mnListCached.get()), mnListTip};
117+
return {mnListCached, mnListTip};
118118
}
119119

120120
void ClientModel::refreshMasternodeList()

src/qt/clientmodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ClientModel : public QObject
7777
int64_t getHeaderTipTime() const;
7878

7979
void setMasternodeList(interfaces::MnListPtr mnList, const CBlockIndex* tip);
80-
std::pair<const interfaces::MnList*, const CBlockIndex*> getMasternodeList() const;
80+
std::pair<interfaces::MnListPtr, const CBlockIndex*> getMasternodeList() const;
8181
void refreshMasternodeList();
8282

8383
void getAllGovernanceObjects(std::vector<CGovernanceObject> &obj);

0 commit comments

Comments
 (0)