Skip to content

Commit 2276339

Browse files
ryanofskysipa
authored andcommitted
Add test for UnregisterAllValidationInterfaces bug
Bug in MainSignalsInstance::Clear could cause validation interface callbacks to be deleted during execution if UnregisterAllValidationInterfaces was called more than once. Bug was introduced in bitcoin/bitcoin#18524 and is fixed by bitcoin/bitcoin#18551
1 parent 3c61abb commit 2276339

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
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()

0 commit comments

Comments
 (0)