mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-12 23:18:14 +01:00
sync: detect double lock from the same thread
Double lock of the same (non-recursive) mutex from the same thread is producing an undefined behavior. Detect this from DEBUG_LOCKORDER and react similarly to the deadlock detection.
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace {
|
||||
template <typename MutexType>
|
||||
@@ -29,6 +32,38 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
|
||||
BOOST_CHECK(!error_thrown);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOCKORDER
|
||||
template <typename MutexType>
|
||||
void TestDoubleLock2(MutexType& m)
|
||||
{
|
||||
ENTER_CRITICAL_SECTION(m);
|
||||
LEAVE_CRITICAL_SECTION(m);
|
||||
}
|
||||
|
||||
template <typename MutexType>
|
||||
void TestDoubleLock(bool should_throw)
|
||||
{
|
||||
const bool prev = g_debug_lockorder_abort;
|
||||
g_debug_lockorder_abort = false;
|
||||
|
||||
MutexType m;
|
||||
ENTER_CRITICAL_SECTION(m);
|
||||
if (should_throw) {
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
TestDoubleLock2(m), std::logic_error, [](const std::logic_error& e) {
|
||||
return strcmp(e.what(), "double lock detected") == 0;
|
||||
});
|
||||
} else {
|
||||
BOOST_CHECK_NO_THROW(TestDoubleLock2(m));
|
||||
}
|
||||
LEAVE_CRITICAL_SECTION(m);
|
||||
|
||||
BOOST_CHECK(LockStackEmpty());
|
||||
|
||||
g_debug_lockorder_abort = prev;
|
||||
}
|
||||
#endif /* DEBUG_LOCKORDER */
|
||||
} // namespace
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup)
|
||||
@@ -55,4 +90,24 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Double lock would produce an undefined behavior. Thus, we only do that if
|
||||
* DEBUG_LOCKORDER is activated to detect it. We don't want non-DEBUG_LOCKORDER
|
||||
* build to produce tests that exhibit known undefined behavior. */
|
||||
#ifdef DEBUG_LOCKORDER
|
||||
BOOST_AUTO_TEST_CASE(double_lock_mutex)
|
||||
{
|
||||
TestDoubleLock<Mutex>(true /* should throw */);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(double_lock_boost_mutex)
|
||||
{
|
||||
TestDoubleLock<boost::mutex>(true /* should throw */);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
|
||||
{
|
||||
TestDoubleLock<RecursiveMutex>(false /* should not throw */);
|
||||
}
|
||||
#endif /* DEBUG_LOCKORDER */
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
Reference in New Issue
Block a user