Bitcoin Core 31.99.0
P2P Digital Currency
sync_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2012-present 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 <sync.h>
6#include <test/util/common.h>
7
8#include <boost/test/unit_test.hpp>
9
10#include <mutex>
11#include <stdexcept>
12
13namespace {
14template <typename MutexType>
15void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
16{
17 {
18 LOCK2(mutex1, mutex2);
19 }
21 {
22#ifdef DEBUG_LOCKORDER
23 BOOST_CHECK_EXCEPTION(LOCK2(mutex2, mutex1), std::logic_error, HasReason{"potential deadlock detected: mutex1 -> mutex2 -> mutex1"});
24#else
25 LOCK2(mutex2, mutex1);
26#endif
27 }
29}
30
31#ifdef DEBUG_LOCKORDER
32template <typename MutexType>
33void TestDoubleLock2(MutexType& m)
34{
35 LOCK(m);
36}
37
38template <typename MutexType>
39void TestDoubleLock(bool should_throw)
40{
41 const bool prev = g_debug_lockorder_abort;
42 g_debug_lockorder_abort = false;
43
44 MutexType m;
45 {
46 LOCK(m);
47 if (should_throw) {
48 BOOST_CHECK_EXCEPTION(TestDoubleLock2(m), std::logic_error,
49 HasReason("double lock detected"));
50 } else {
51 BOOST_CHECK_NO_THROW(TestDoubleLock2(m));
52 }
53 }
55
56 g_debug_lockorder_abort = prev;
57}
58#endif /* DEBUG_LOCKORDER */
59
60template <typename MutexType>
61void TestInconsistentLockOrderDetected(MutexType& mutex1, MutexType& mutex2)
62{
63 {
64 WAIT_LOCK(mutex1, lock1);
65 LOCK(mutex2);
66#ifdef DEBUG_LOCKORDER
67 BOOST_CHECK_EXCEPTION(REVERSE_LOCK(lock1, mutex1), std::logic_error, HasReason("mutex1 was not most recent critical section locked"));
68#endif // DEBUG_LOCKORDER
69 }
71}
72} // namespace
73
74BOOST_AUTO_TEST_SUITE(sync_tests)
75
76BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
77{
78 #ifdef DEBUG_LOCKORDER
79 bool prev = g_debug_lockorder_abort;
80 g_debug_lockorder_abort = false;
81 #endif
82
83 RecursiveMutex rmutex1, rmutex2;
84 TestPotentialDeadLockDetected(rmutex1, rmutex2);
85 // The second test ensures that lock tracking data have not been broken by exception.
86 TestPotentialDeadLockDetected(rmutex1, rmutex2);
87
88 Mutex mutex1, mutex2;
89 TestPotentialDeadLockDetected(mutex1, mutex2);
90 // The second test ensures that lock tracking data have not been broken by exception.
91 TestPotentialDeadLockDetected(mutex1, mutex2);
92
93 #ifdef DEBUG_LOCKORDER
94 g_debug_lockorder_abort = prev;
95 #endif
96}
97
98/* Double lock would produce an undefined behavior. Thus, we only do that if
99 * DEBUG_LOCKORDER is activated to detect it. We don't want non-DEBUG_LOCKORDER
100 * build to produce tests that exhibit known undefined behavior. */
101#ifdef DEBUG_LOCKORDER
102BOOST_AUTO_TEST_CASE(double_lock_mutex)
103{
104 TestDoubleLock<Mutex>(/*should_throw=*/true);
105}
106
107BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
108{
109 TestDoubleLock<RecursiveMutex>(/*should_throw=*/false);
110}
111#endif /* DEBUG_LOCKORDER */
112
113BOOST_AUTO_TEST_CASE(inconsistent_lock_order_detected)
114{
115#ifdef DEBUG_LOCKORDER
116 bool prev = g_debug_lockorder_abort;
117 g_debug_lockorder_abort = false;
118#endif // DEBUG_LOCKORDER
119
120 RecursiveMutex rmutex1, rmutex2;
121 TestInconsistentLockOrderDetected(rmutex1, rmutex2);
122 // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical)
123 // the lock tracking data must not have been broken by exception.
124 TestInconsistentLockOrderDetected(rmutex1, rmutex2);
125
126 Mutex mutex1, mutex2;
127 TestInconsistentLockOrderDetected(mutex1, mutex2);
128 // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical)
129 // the lock tracking data must not have been broken by exception.
130 TestInconsistentLockOrderDetected(mutex1, mutex2);
131
132#ifdef DEBUG_LOCKORDER
133 g_debug_lockorder_abort = prev;
134#endif // DEBUG_LOCKORDER
135}
136
BOOST_CHECK_EXCEPTION predicates to check the specific validation error.
Definition: common.h:19
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EXCEPTION(HTTPHeaders{}.Read(reader), std::runtime_error, HasReason{"Empty HTTP header name"})
#define BOOST_CHECK_NO_THROW(stmt)
Definition: object.cpp:27
#define BOOST_CHECK(expr)
Definition: object.cpp:16
#define WAIT_LOCK(cs, name)
Definition: sync.h:274
#define LOCK2(cs1, cs2)
Definition: sync.h:269
#define REVERSE_LOCK(g, cs)
Definition: sync.h:254
#define LOCK(cs)
Definition: sync.h:268
bool LockStackEmpty()
Definition: sync.h:75
BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
Definition: sync_tests.cpp:76