Skip to content

Commit 89f71c6

Browse files
committed
c++11: don't throw from the reverselock destructor
noexcept is default for destructors as of c++11. By throwing in reverselock's destructor if it's lock has been tampered with, the likely result is std::terminate being called. Indeed that happened before this change. Once reverselock has taken another lock (its ctor didn't throw), it makes no sense to try to grab or lock the parent lock. That is be broken/undefined behavior depending on the parent lock's implementation, but it shouldn't cause the reverselock to fail to re-lock when destroyed. To avoid those problems, simply swap the parent lock's contents with a dummy for the duration of the lock. That will ensure that any undefined behavior is caught at the call-site rather than the reverse lock's destruction. Barring a failed mutex unlock which would be indicative of a larger problem, the destructor should now never throw.
1 parent 76ac35f commit 89f71c6

File tree

2 files changed

+10
-11
lines changed

2 files changed

+10
-11
lines changed

src/reverselock.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@ class reverse_lock
1515

1616
explicit reverse_lock(Lock& lock) : lock(lock) {
1717
lock.unlock();
18+
lock.swap(templock);
1819
}
1920

2021
~reverse_lock() {
21-
lock.lock();
22+
templock.lock();
23+
templock.swap(lock);
2224
}
2325

2426
private:
2527
reverse_lock(reverse_lock const&);
2628
reverse_lock& operator=(reverse_lock const&);
2729

2830
Lock& lock;
31+
Lock templock;
2932
};
3033

3134
#endif // BITCOIN_REVERSELOCK_H

src/test/reverselock_tests.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,18 @@ BOOST_AUTO_TEST_CASE(reverselock_errors)
4242
BOOST_CHECK(failed);
4343
BOOST_CHECK(!lock.owns_lock());
4444

45-
// Make sure trying to lock a lock after it has been reverse locked fails
46-
failed = false;
47-
bool locked = false;
45+
// Locking the original lock after it has been taken by a reverse lock
46+
// makes no sense. Ensure that the original lock no longer owns the lock
47+
// after giving it to a reverse one.
4848

4949
lock.lock();
5050
BOOST_CHECK(lock.owns_lock());
51-
52-
try {
51+
{
5352
reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
54-
lock.lock();
55-
locked = true;
56-
} catch(...) {
57-
failed = true;
53+
BOOST_CHECK(!lock.owns_lock());
5854
}
5955

60-
BOOST_CHECK(locked && failed);
56+
BOOST_CHECK(failed);
6157
BOOST_CHECK(lock.owns_lock());
6258
}
6359

0 commit comments

Comments
 (0)