diff options
author | Russell Yanofsky <russ@yanofsky.org> | 2020-04-07 08:03:39 -0400 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2020-04-07 12:54:41 -0700 |
commit | 2276339a176f83ffe8ceefb3e41ecca8601aa13b (patch) | |
tree | fe4e86b7ebe0b2aa3f24c9f5250e827e55b736fe | |
parent | 3c61abbbc847d725f30d169278d84655571407c1 (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.include | 1 | ||||
-rw-r--r-- | src/test/validationinterface_tests.cpp | 63 |
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() |