Skip to content

Commit 1f70185

Browse files
author
MarcoFalke
committed
Merge #18551: Do not clear validationinterface entries being executed
2276339 Add test for UnregisterAllValidationInterfaces bug (Russell Yanofsky) 3c61abb Do not clear validationinterface entries being executed (Pieter Wuille) Pull request description: The previous code for MainSignalsInstance::Clear would decrement the reference count of every interface, including ones that were already Unregister()ed but still being executed. This fixes the issue pointed out here: https://github.com/bitcoin/bitcoin/pull/18524/files#r404395685 . It's not currently observable. ACKs for top commit: jonasschnelli: utACK 2276339 - reviewed code and test (thanks @ryanofsky for adding the test). MarcoFalke: ACK 2276339 🎎 ryanofsky: Code review ACK 2276339. No change to bugfix, just rebased and new test commit added since last review Tree-SHA512: c1d68e7c681a45c6cadc84e407c2266bcb4b12d34264e1232a61c4eadb74b551231c5a3b1d041de39f507aef4dfa7d4589b8bfe1833f069c739c6270d2a05dbe
2 parents 1b151e3 + 2276339 commit 1f70185

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ BITCOIN_TESTS =\
239239
test/util_tests.cpp \
240240
test/validation_block_tests.cpp \
241241
test/validation_flush_tests.cpp \
242+
test/validationinterface_tests.cpp \
242243
test/versionbits_tests.cpp
243244

244245
if ENABLE_WALLET
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 2020 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <boost/test/unit_test.hpp>
6+
7+
#include <consensus/validation.h>
8+
#include <primitives/block.h>
9+
#include <scheduler.h>
10+
#include <util/check.h>
11+
#include <validationinterface.h>
12+
13+
BOOST_AUTO_TEST_SUITE(validationinterface_tests)
14+
15+
class TestInterface : public CValidationInterface
16+
{
17+
public:
18+
TestInterface(std::function<void()> on_call = nullptr, std::function<void()> on_destroy = nullptr)
19+
: m_on_call(std::move(on_call)), m_on_destroy(std::move(on_destroy))
20+
{
21+
}
22+
virtual ~TestInterface()
23+
{
24+
if (m_on_destroy) m_on_destroy();
25+
}
26+
void BlockChecked(const CBlock& block, const BlockValidationState& state) override
27+
{
28+
if (m_on_call) m_on_call();
29+
}
30+
static void Call()
31+
{
32+
CBlock block;
33+
BlockValidationState state;
34+
GetMainSignals().BlockChecked(block, state);
35+
}
36+
std::function<void()> m_on_call;
37+
std::function<void()> m_on_destroy;
38+
};
39+
40+
// Regression test to ensure UnregisterAllValidationInterfaces calls don't
41+
// destroy a validation interface while it is being called. Bug:
42+
// https://github.com/bitcoin/bitcoin/pull/18551
43+
BOOST_AUTO_TEST_CASE(unregister_all_during_call)
44+
{
45+
bool destroyed = false;
46+
47+
CScheduler scheduler;
48+
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
49+
RegisterSharedValidationInterface(std::make_shared<TestInterface>(
50+
[&] {
51+
// First call should decrements reference count 2 -> 1
52+
UnregisterAllValidationInterfaces();
53+
BOOST_CHECK(!destroyed);
54+
// Second call should not decrement reference count 1 -> 0
55+
UnregisterAllValidationInterfaces();
56+
BOOST_CHECK(!destroyed);
57+
},
58+
[&] { destroyed = true; }));
59+
TestInterface::Call();
60+
BOOST_CHECK(destroyed);
61+
}
62+
63+
BOOST_AUTO_TEST_SUITE_END()

src/validationinterface.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ struct MainSignalsInstance {
6767
void Clear()
6868
{
6969
LOCK(m_mutex);
70-
for (auto it = m_list.begin(); it != m_list.end();) {
71-
it = --it->count ? std::next(it) : m_list.erase(it);
70+
for (const auto& entry : m_map) {
71+
if (!--entry.second->count) m_list.erase(entry.second);
7272
}
7373
m_map.clear();
7474
}

0 commit comments

Comments
 (0)