aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Yanofsky <russ@yanofsky.org>2020-04-07 08:03:39 -0400
committerPieter Wuille <pieter.wuille@gmail.com>2020-04-07 12:54:41 -0700
commit2276339a176f83ffe8ceefb3e41ecca8601aa13b (patch)
treefe4e86b7ebe0b2aa3f24c9f5250e827e55b736fe
parent3c61abbbc847d725f30d169278d84655571407c1 (diff)
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 https://github.com/bitcoin/bitcoin/pull/18524 and is fixed by https://github.com/bitcoin/bitcoin/pull/18551
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/test/validationinterface_tests.cpp63
2 files changed, 64 insertions, 0 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index c3021743f4..3443ee089d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -239,6 +239,7 @@ BITCOIN_TESTS =\
test/util_tests.cpp \
test/validation_block_tests.cpp \
test/validation_flush_tests.cpp \
+ test/validationinterface_tests.cpp \
test/versionbits_tests.cpp
if ENABLE_WALLET
diff --git a/src/test/validationinterface_tests.cpp b/src/test/validationinterface_tests.cpp
new file mode 100644
index 0000000000..b4aa2f0f3a
--- /dev/null
+++ b/src/test/validationinterface_tests.cpp
@@ -0,0 +1,63 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <boost/test/unit_test.hpp>
+
+#include <consensus/validation.h>
+#include <primitives/block.h>
+#include <scheduler.h>
+#include <util/check.h>
+#include <validationinterface.h>
+
+BOOST_AUTO_TEST_SUITE(validationinterface_tests)
+
+class TestInterface : public CValidationInterface
+{
+public:
+ TestInterface(std::function<void()> on_call = nullptr, std::function<void()> on_destroy = nullptr)
+ : m_on_call(std::move(on_call)), m_on_destroy(std::move(on_destroy))
+ {
+ }
+ virtual ~TestInterface()
+ {
+ if (m_on_destroy) m_on_destroy();
+ }
+ void BlockChecked(const CBlock& block, const BlockValidationState& state) override
+ {
+ if (m_on_call) m_on_call();
+ }
+ static void Call()
+ {
+ CBlock block;
+ BlockValidationState state;
+ GetMainSignals().BlockChecked(block, state);
+ }
+ std::function<void()> m_on_call;
+ std::function<void()> m_on_destroy;
+};
+
+// Regression test to ensure UnregisterAllValidationInterfaces calls don't
+// destroy a validation interface while it is being called. Bug:
+// https://github.com/bitcoin/bitcoin/pull/18551
+BOOST_AUTO_TEST_CASE(unregister_all_during_call)
+{
+ bool destroyed = false;
+
+ CScheduler scheduler;
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+ RegisterSharedValidationInterface(std::make_shared<TestInterface>(
+ [&] {
+ // First call should decrements reference count 2 -> 1
+ UnregisterAllValidationInterfaces();
+ BOOST_CHECK(!destroyed);
+ // Second call should not decrement reference count 1 -> 0
+ UnregisterAllValidationInterfaces();
+ BOOST_CHECK(!destroyed);
+ },
+ [&] { destroyed = true; }));
+ TestInterface::Call();
+ BOOST_CHECK(destroyed);
+}
+
+BOOST_AUTO_TEST_SUITE_END()