-
Notifications
You must be signed in to change notification settings - Fork 35.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tests: Make test_bitcoin pass under ThreadSanitzer (clang). Fix lock-order-inversion (potential deadlock). #12882
tests: Make test_bitcoin pass under ThreadSanitzer (clang). Fix lock-order-inversion (potential deadlock). #12882
Conversation
@practicalswift Can you include some more information about recreating this? I've done a naive:
(macOS 10.13.4 with XCode 9.3) and am having trouble recreating the issue. |
@fanquake I just verified using clang version 7.0.0 (trunk) under Linux using the following commands:
|
It could help reviewers if you explained why it is a deadlock in the OP and then also describe why your patch fixes it. |
@MarcoFalke Ah, sorry: the reason for the potential deadlock warning (lock-order-inversion) is simply that the lock order between After this commit the following lock order is used:
Prior to this commit the following lock order was also used:
This is part of the
|
Thanks @practicalswift.
Can confirm that this patch make the warning disappear. |
So what exactly needs |
@MarcoFalke |
Can't vouch for that, but it seems so. |
@practicalswift Mind to update according to my suggestion? |
@MarcoFalke Do you mean with more narrowly scoped locks? Something like this? diff --git a/src/net_processing.h b/src/net_processing.h
index 195d0d2..6802887 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -72,7 +72,7 @@ public:
* @param[in] interrupt Interrupt condition for processing threads
* @return True if there is more work to be done
*/
- bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override;
+ bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index abc31e6..3d1ac7a 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -66,25 +66,40 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
dummyNode1.fSuccessfullyConnected = true;
// This test requires that we have a chain with non-zero work.
- LOCK(cs_main);
- BOOST_CHECK(chainActive.Tip() != nullptr);
- BOOST_CHECK(chainActive.Tip()->nChainWork > 0);
+ {
+ LOCK(cs_main);
+ BOOST_CHECK(chainActive.Tip() != nullptr);
+ BOOST_CHECK(chainActive.Tip()->nChainWork > 0);
+ }
// Test starts here
- LOCK(dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
- LOCK(dummyNode1.cs_vSend);
- BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
- dummyNode1.vSendMsg.clear();
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ }
+ {
+ LOCK2(cs_main, dummyNode1.cs_vSend);
+ BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ dummyNode1.vSendMsg.clear();
+ }
int64_t nStartTime = GetTime();
// Wait 21 minutes
SetMockTime(nStartTime+21*60);
- peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
- BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ }
+ {
+ LOCK2(cs_main, dummyNode1.cs_vSend);
+ BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ }
// Wait 3 more minutes
SetMockTime(nStartTime+24*60);
- peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in disconnect
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in disconnect
+ }
BOOST_CHECK(dummyNode1.fDisconnect == true);
SetMockTime(0);
@@ -190,8 +205,10 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
}
- LOCK(dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ }
BOOST_CHECK(connman->IsBanned(addr1));
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
@@ -205,15 +222,20 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
LOCK(cs_main);
Misbehaving(dummyNode2.GetId(), 50);
}
- LOCK(dummyNode2.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode2, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode2.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode2, interruptDummy);
+ }
BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
{
LOCK(cs_main);
Misbehaving(dummyNode2.GetId(), 50);
}
- peerLogic->SendMessages(&dummyNode2, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode2.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode2, interruptDummy);
+ }
BOOST_CHECK(connman->IsBanned(addr2));
bool dummy;
@@ -237,20 +259,28 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 100);
}
- LOCK(dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ }
BOOST_CHECK(!connman->IsBanned(addr1));
{
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 10);
}
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ }
BOOST_CHECK(!connman->IsBanned(addr1));
{
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 1);
}
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ }
BOOST_CHECK(connman->IsBanned(addr1));
gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
@@ -277,8 +307,10 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
LOCK(cs_main);
Misbehaving(dummyNode.GetId(), 100);
}
- LOCK(dummyNode.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode, interruptDummy);
+ {
+ LOCK2(cs_main, dummyNode.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode, interruptDummy);
+ }
BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60); |
@practicalswift Looks very verbose, but fine to me. Shouldn't hurt to document the locking assumtions in tests? |
@MarcoFalke Do you have an example on how to document the locking assumption in the tests? That is beyond the suggested documentation in form of the annotation:
|
I think your suggested diff is fine |
8124d08
to
8043568
Compare
@MarcoFalke Applied. Please review :-) |
src/test/DoS_tests.cpp
Outdated
LOCK(dummyNode1.cs_sendProcessing); | ||
peerLogic->SendMessages(&dummyNode1, interruptDummy); | ||
{ | ||
LOCK2(cs_main, dummyNode1.cs_sendProcessing); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Seems you already locked cs_main
in the first line of the test case, so a LOCK(dummyNode1.cs_sendProcessing);
should suffice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
8043568
to
640523f
Compare
@MarcoFalke Thanks! Please review updated version :-) |
utACK 640523f77882c655ade8373eea1062691bf72b98 |
Needs rebase |
…ported by TSAN. Makes `src/test/test_bitcoin --run_test=DoS_tests` pass also when compiled with TreadSanitizer (`./configure --with-sanitizers=thread`).
640523f
to
9fdf05d
Compare
Rebased! Please re-review :-) |
utACK 9fdf05d |
1 similar comment
utACK 9fdf05d |
…ng). Fix lock-order-inversion (potential deadlock). 9fdf05d tests: Fix lock-order-inversion (potential deadlock) in DoS_tests. Reported by TSAN. (practicalswift) Pull request description: Fix lock-order-inversion (potential deadlock) in `DoS_tests`. Reported by Clang's TSAN. Makes `src/test/test_bitcoin` pass also when compiled with TreadSanitizer (`./configure --with-sanitizers=thread` with `clang`). Tree-SHA512: 41403bb7b6e26bdf1b830b5699e27c637d522bae1799d2a19ed4b68b21b2555438b42170d8b1189613beb32a69b76a65175d29a83f5f4e493896c3d0d94ae26d
Can we enable this in travis, so it wouldn't happen again, please? |
…er (clang). Fix lock-order-inversion (potential deadlock). 9fdf05d tests: Fix lock-order-inversion (potential deadlock) in DoS_tests. Reported by TSAN. (practicalswift) Pull request description: Fix lock-order-inversion (potential deadlock) in `DoS_tests`. Reported by Clang's TSAN. Makes `src/test/test_bitcoin` pass also when compiled with TreadSanitizer (`./configure --with-sanitizers=thread` with `clang`). Tree-SHA512: 41403bb7b6e26bdf1b830b5699e27c637d522bae1799d2a19ed4b68b21b2555438b42170d8b1189613beb32a69b76a65175d29a83f5f4e493896c3d0d94ae26d
…er (clang). Fix lock-order-inversion (potential deadlock). 9fdf05d tests: Fix lock-order-inversion (potential deadlock) in DoS_tests. Reported by TSAN. (practicalswift) Pull request description: Fix lock-order-inversion (potential deadlock) in `DoS_tests`. Reported by Clang's TSAN. Makes `src/test/test_bitcoin` pass also when compiled with TreadSanitizer (`./configure --with-sanitizers=thread` with `clang`). Tree-SHA512: 41403bb7b6e26bdf1b830b5699e27c637d522bae1799d2a19ed4b68b21b2555438b42170d8b1189613beb32a69b76a65175d29a83f5f4e493896c3d0d94ae26d
…er (clang). Fix lock-order-inversion (potential deadlock). 9fdf05d tests: Fix lock-order-inversion (potential deadlock) in DoS_tests. Reported by TSAN. (practicalswift) Pull request description: Fix lock-order-inversion (potential deadlock) in `DoS_tests`. Reported by Clang's TSAN. Makes `src/test/test_bitcoin` pass also when compiled with TreadSanitizer (`./configure --with-sanitizers=thread` with `clang`). Tree-SHA512: 41403bb7b6e26bdf1b830b5699e27c637d522bae1799d2a19ed4b68b21b2555438b42170d8b1189613beb32a69b76a65175d29a83f5f4e493896c3d0d94ae26d
…er (clang). Fix lock-order-inversion (potential deadlock). 9fdf05d tests: Fix lock-order-inversion (potential deadlock) in DoS_tests. Reported by TSAN. (practicalswift) Pull request description: Fix lock-order-inversion (potential deadlock) in `DoS_tests`. Reported by Clang's TSAN. Makes `src/test/test_bitcoin` pass also when compiled with TreadSanitizer (`./configure --with-sanitizers=thread` with `clang`). Tree-SHA512: 41403bb7b6e26bdf1b830b5699e27c637d522bae1799d2a19ed4b68b21b2555438b42170d8b1189613beb32a69b76a65175d29a83f5f4e493896c3d0d94ae26d
Fix lock-order-inversion (potential deadlock) in
DoS_tests
. Reported by Clang's TSAN.Makes
src/test/test_bitcoin
pass also when compiled with TreadSanitizer (./configure --with-sanitizers=thread
withclang
).