Skip to content

Commit 65c4bbe

Browse files
author
MarcoFalke
committed
Merge #16034: refactoring: Rename LockAnnotation to LockAssertion and add run-time check to it
9f85e9c scripted-diff: Rename LockAnnotation to LockAssertion (practicalswift) de9b5db Make sure the compile-time locking promises given via LockAnnotation:s hold also in practice at runtime (ifdef DEBUG_LOCKORDER) (practicalswift) 3a80944 Move LockAnnotation to make it reflect the truth (practicalswift) cc25885 Move LockAnnotation from threadsafety.h (imported code) to sync.h (our code) (practicalswift) Pull request description: `LockAnnotation lock(mutex);` is a guarantee to the compiler thread-analysis that `mutex` is locked (when it couldn't be determined otherwise). Before this PR it was possible to make the mistake of adding a `LockAnnotation` where the correct mutex is _not_ held. This in turn makes the thread-analysis reasoning being based on incorrect premises. This PR adds an assertion in the `LockAnnotation` ctor which checks that the guarantees given by us at compile-time are held also in practice (`ifdef DEBUG_LOCKORDER`). Issues like the one described in #16028 will be discovered immediately with this PR merged. Changes in this PR: * Move `LockAnnotation` from `threadsafety.h` (imported code) to `sync.h` (our code) * Move `LockAnnotation` in `wallet_tests` to make it reflect the truth * Make sure the compile-time locking promises given via `LockAnnotation`:s hold also in practice at runtime (`ifdef DEBUG_LOCKORDER`) * Rename `LockAnnotation` to `LockAssertion` ACKs for commit 9f85e9: ryanofsky: utACK 9f85e9c. No changes at all since last review except clean rebase after base PR #16033 was merged Tree-SHA512: fb80e78fe362adfd6ea8405bcb142c09b99f834fe8be4397282b223ca2c3a2bb9719a074a47a043b44757f840b239a6fcd2f98d14771f8729204834ecf608c3a
2 parents 0b058ba + 9f85e9c commit 65c4bbe

File tree

5 files changed

+33
-30
lines changed

5 files changed

+33
-30
lines changed

src/interfaces/chain.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
4141
{
4242
Optional<int> getHeight() override
4343
{
44-
LockAnnotation lock(::cs_main);
44+
LockAssertion lock(::cs_main);
4545
int height = ::ChainActive().Height();
4646
if (height >= 0) {
4747
return height;
@@ -50,7 +50,7 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
5050
}
5151
Optional<int> getBlockHeight(const uint256& hash) override
5252
{
53-
LockAnnotation lock(::cs_main);
53+
LockAssertion lock(::cs_main);
5454
CBlockIndex* block = LookupBlockIndex(hash);
5555
if (block && ::ChainActive().Contains(block)) {
5656
return block->nHeight;
@@ -65,34 +65,34 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
6565
}
6666
uint256 getBlockHash(int height) override
6767
{
68-
LockAnnotation lock(::cs_main);
68+
LockAssertion lock(::cs_main);
6969
CBlockIndex* block = ::ChainActive()[height];
7070
assert(block != nullptr);
7171
return block->GetBlockHash();
7272
}
7373
int64_t getBlockTime(int height) override
7474
{
75-
LockAnnotation lock(::cs_main);
75+
LockAssertion lock(::cs_main);
7676
CBlockIndex* block = ::ChainActive()[height];
7777
assert(block != nullptr);
7878
return block->GetBlockTime();
7979
}
8080
int64_t getBlockMedianTimePast(int height) override
8181
{
82-
LockAnnotation lock(::cs_main);
82+
LockAssertion lock(::cs_main);
8383
CBlockIndex* block = ::ChainActive()[height];
8484
assert(block != nullptr);
8585
return block->GetMedianTimePast();
8686
}
8787
bool haveBlockOnDisk(int height) override
8888
{
89-
LockAnnotation lock(::cs_main);
89+
LockAssertion lock(::cs_main);
9090
CBlockIndex* block = ::ChainActive()[height];
9191
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
9292
}
9393
Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override
9494
{
95-
LockAnnotation lock(::cs_main);
95+
LockAssertion lock(::cs_main);
9696
CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height);
9797
if (block) {
9898
if (hash) *hash = block->GetBlockHash();
@@ -102,7 +102,7 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
102102
}
103103
Optional<int> findPruned(int start_height, Optional<int> stop_height) override
104104
{
105-
LockAnnotation lock(::cs_main);
105+
LockAssertion lock(::cs_main);
106106
if (::fPruneMode) {
107107
CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip();
108108
while (block && block->nHeight >= start_height) {
@@ -116,7 +116,7 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
116116
}
117117
Optional<int> findFork(const uint256& hash, Optional<int>* height) override
118118
{
119-
LockAnnotation lock(::cs_main);
119+
LockAssertion lock(::cs_main);
120120
const CBlockIndex* block = LookupBlockIndex(hash);
121121
const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr;
122122
if (height) {
@@ -133,25 +133,25 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
133133
}
134134
CBlockLocator getTipLocator() override
135135
{
136-
LockAnnotation lock(::cs_main);
136+
LockAssertion lock(::cs_main);
137137
return ::ChainActive().GetLocator();
138138
}
139139
Optional<int> findLocatorFork(const CBlockLocator& locator) override
140140
{
141-
LockAnnotation lock(::cs_main);
141+
LockAssertion lock(::cs_main);
142142
if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) {
143143
return fork->nHeight;
144144
}
145145
return nullopt;
146146
}
147147
bool checkFinalTx(const CTransaction& tx) override
148148
{
149-
LockAnnotation lock(::cs_main);
149+
LockAssertion lock(::cs_main);
150150
return CheckFinalTx(tx);
151151
}
152152
bool submitToMemoryPool(const CTransactionRef& tx, CAmount absurd_fee, CValidationState& state) override
153153
{
154-
LockAnnotation lock(::cs_main);
154+
LockAssertion lock(::cs_main);
155155
return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */,
156156
false /* bypass limits */, absurd_fee);
157157
}

src/qt/test/wallettests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ void TestGUI()
145145
}
146146
{
147147
auto locked_chain = wallet->chain().lock();
148-
LockAnnotation lock(::cs_main);
148+
LockAssertion lock(::cs_main);
149149

150150
WalletRescanReserver reserver(wallet.get());
151151
reserver.reserve();

src/sync.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,4 +304,18 @@ class CSemaphoreGrant
304304
}
305305
};
306306

307+
// Utility class for indicating to compiler thread analysis that a mutex is
308+
// locked (when it couldn't be determined otherwise).
309+
struct SCOPED_LOCKABLE LockAssertion
310+
{
311+
template <typename Mutex>
312+
explicit LockAssertion(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
313+
{
314+
#ifdef DEBUG_LOCKORDER
315+
AssertLockHeld(mutex);
316+
#endif
317+
}
318+
~LockAssertion() UNLOCK_FUNCTION() {}
319+
};
320+
307321
#endif // BITCOIN_SYNC_H

src/threadsafety.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,4 @@
5454
#define ASSERT_EXCLUSIVE_LOCK(...)
5555
#endif // __GNUC__
5656

57-
// Utility class for indicating to compiler thread analysis that a mutex is
58-
// locked (when it couldn't be determined otherwise).
59-
struct SCOPED_LOCKABLE LockAnnotation
60-
{
61-
template <typename Mutex>
62-
explicit LockAnnotation(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
63-
{
64-
}
65-
~LockAnnotation() UNLOCK_FUNCTION() {}
66-
};
67-
6857
#endif // BITCOIN_THREADSAFETY_H

src/wallet/test/wallet_tests.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
4444

4545
auto chain = interfaces::MakeChain();
4646
auto locked_chain = chain->lock();
47-
LockAnnotation lock(::cs_main);
47+
LockAssertion lock(::cs_main);
4848

4949
// Verify ScanForWalletTransactions accommodates a null start block.
5050
{
@@ -123,7 +123,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
123123

124124
auto chain = interfaces::MakeChain();
125125
auto locked_chain = chain->lock();
126-
LockAnnotation lock(::cs_main);
126+
LockAssertion lock(::cs_main);
127127

128128
// Prune the older block file.
129129
PruneOneBlockFile(oldTip->GetBlockPos().nFile);
@@ -190,7 +190,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
190190

191191
auto chain = interfaces::MakeChain();
192192
auto locked_chain = chain->lock();
193-
LockAnnotation lock(::cs_main);
193+
LockAssertion lock(::cs_main);
194194

195195
std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string();
196196

@@ -248,7 +248,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
248248
CWalletTx wtx(&wallet, m_coinbase_txns.back());
249249

250250
auto locked_chain = chain->lock();
251-
LockAnnotation lock(::cs_main);
251+
LockAssertion lock(::cs_main);
252252
LOCK(wallet.cs_wallet);
253253

254254
wtx.hashBlock = ::ChainActive().Tip()->GetBlockHash();
@@ -272,8 +272,8 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
272272
SetMockTime(mockTime);
273273
CBlockIndex* block = nullptr;
274274
if (blockTime > 0) {
275-
LockAnnotation lock(::cs_main);
276275
auto locked_chain = wallet.chain().lock();
276+
LockAssertion lock(::cs_main);
277277
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
278278
assert(inserted.second);
279279
const uint256& hash = inserted.first->first;

0 commit comments

Comments
 (0)