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