Merge #18742: miner: Avoid stack-use-after-return in validationinterface

7777f2a4bb miner: Avoid stack-use-after-return in validationinterface (MarcoFalke)
fa5ceb25fc test: Remove UninterruptibleSleep from test and replace it by SyncWithValidationInterfaceQueue (MarcoFalke)
fa770ce7fe validationinterface: Rework documentation, Rename pwalletIn to callbacks (MarcoFalke)
fab6d060ce test: Add unregister_validation_interface_race test (MarcoFalke)

Pull request description:

  When a validationinterface has itself unregistered in one thread, but is about to get executed in another thread [1], there is a race:

  * The validationinterface destructing itself
  * The validationinterface getting dereferenced for execution

  [1] 64139803f1/src/validationinterface.cpp (L82-L83)

  This happens in the miner. More generally it happens everywhere where at least one thread is generating notifications and another one is unregistering a validationinterface.

  This issue has been fixed in commit ab31b9d6fe, but the fix has not been applied to the miner.

  Example where this happened in practice: https://travis-ci.org/github/bitcoin/bitcoin/jobs/675322230#L4414

ACKs for top commit:
  promag:
    Code review ACK 7777f2a4bb.
  laanwj:
    Code review ACK 7777f2a4bb

Tree-SHA512: 8087119243c71ba18a823a63515f3730d127162625d8729024278b447af29e2ff206f4840ee3d90bf84f93a2c5ab73b76c7e7044c83aa93b5b51047a166ec3d3
This commit is contained in:
fanquake
2020-05-14 20:17:38 +08:00
5 changed files with 75 additions and 34 deletions

View File

@@ -874,7 +874,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
return result;
}
class submitblock_StateCatcher : public CValidationInterface
class submitblock_StateCatcher final : public CValidationInterface
{
public:
uint256 hash;
@@ -942,17 +942,17 @@ static UniValue submitblock(const JSONRPCRequest& request)
}
bool new_block;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
bool accepted = ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
UnregisterValidationInterface(&sc);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
}
if (!sc.found) {
if (!sc->found) {
return "inconclusive";
}
return BIP22ValidationResult(sc.state);
return BIP22ValidationResult(sc->state);
}
static UniValue submitheader(const JSONRPCRequest& request)