Skip to content

Commit 3cf8acf

Browse files
committed
Add locking on the chain index vector.
This alleviates a data race reported by tsan (concurrent access to size(), operator[], and resize()).
1 parent 3140a94 commit 3cf8acf

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

src/chain.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* CChain implementation
1717
*/
1818
void CChain::SetTip(CBlockIndex *pindex) {
19+
LOCK(cs_vchain);
1920
if (pindex == nullptr) {
2021
vChain.clear();
2122
return;
@@ -68,6 +69,7 @@ const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
6869

6970
CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
7071
{
72+
LOCK(cs_vchain);
7173
std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
7274
[](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
7375
return (lower == vChain.end() ? nullptr : *lower);

src/chain.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -725,28 +725,36 @@ class CDiskBlockIndex : public CBlockIndex
725725
/** An in-memory indexed chain of blocks. */
726726
class CChain {
727727
private:
728-
std::vector<CBlockIndex*> vChain;
728+
mutable CCriticalSection cs_vchain;
729+
std::vector<CBlockIndex*> vChain GUARDED_BY(cs_vchain);
729730

730731
public:
731732
/** Returns the index entry for the genesis block of this chain, or nullptr if none. */
732733
CBlockIndex *Genesis() const {
734+
LOCK(cs_vchain);
733735
return vChain.size() > 0 ? vChain[0] : nullptr;
734736
}
735737

736738
/** Returns the index entry for the tip of this chain, or nullptr if none. */
737739
CBlockIndex *Tip() const {
740+
LOCK(cs_vchain);
738741
return vChain.size() > 0 ? vChain[vChain.size() - 1] : nullptr;
739742
}
740743

741744
/** Returns the index entry at a particular height in this chain, or nullptr if no such height exists. */
742745
CBlockIndex *operator[](int nHeight) const {
746+
LOCK(cs_vchain);
743747
if (nHeight < 0 || nHeight >= (int)vChain.size())
744748
return nullptr;
745749
return vChain[nHeight];
746750
}
747751

748752
/** Compare two chains efficiently. */
749753
friend bool operator==(const CChain &a, const CChain &b) {
754+
// Maintain consistent lock order.
755+
if (&b < &a) return b == a;
756+
757+
LOCK2(a.cs_vchain, b.cs_vchain);
750758
return a.vChain.size() == b.vChain.size() &&
751759
a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1];
752760
}
@@ -758,6 +766,7 @@ class CChain {
758766

759767
/** Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip. */
760768
CBlockIndex *Next(const CBlockIndex *pindex) const {
769+
LOCK(cs_vchain);
761770
if (Contains(pindex))
762771
return (*this)[pindex->nHeight + 1];
763772
else
@@ -766,6 +775,7 @@ class CChain {
766775

767776
/** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */
768777
int Height() const {
778+
LOCK(cs_vchain);
769779
return vChain.size() - 1;
770780
}
771781

0 commit comments

Comments
 (0)