Skip to content

Conversation

adamjonas
Copy link
Member

Re-opening #11342 (taking suggestions from comments) which adds sanity asserts for return value of CBlockIndex::GetAncestor() where appropriate.

In validation.cpp CheckSequenceLocks, check the return value of tip->GetAncestor(maxInputHeight) stored into lp->maxInputBlock. If it ever returns nullptr because the ancestor isn't found, it's going to be a bad bug to keep going, since a LockPoints object with the maxInputBlock member set to nullptr signifies no relative lock time.

In other places, the added asserts would prevent accidental dereferencing of a null pointer which is undefined behavior.

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK.

@practicalswift
Copy link
Contributor

Concept ACK

Explicit is better than implicit.

In case the assumptions do not hold then a predictable assertion failure is the better alternative.

@adamjonas adamjonas force-pushed the assert_get_ancestor branch from ddad4b0 to 22cca81 Compare October 29, 2019 19:16
@adamjonas adamjonas force-pushed the assert_get_ancestor branch from 22cca81 to 59f51d5 Compare October 29, 2019 19:40
@jnewbery
Copy link
Contributor

Code review ACK 59f51d5

@practicalswift
Copy link
Contributor

practicalswift commented Nov 1, 2019

@adamjonas Thanks for making implicit assumptions explicit by adding assertions and documentation.

If you want to continue working on making currently implicit != nullptr assumptions explicit you might want to try compiling with -Wnull-dereference to see what the compiler regards as potential null pointer dereferences.

FWIW gcc 7.4.0 with -Wnull-dereference against current master:

interfaces/chain.cpp:360:63: warning: potential null pointer dereference [-Wnull-dereference]
interfaces/node.cpp:191:56: warning: potential null pointer dereference [-Wnull-dereference]
miner.cpp:333:18: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1206:19: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1299:52: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1305:43: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1431:182: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1499:65: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1619:78: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1637:45: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1711:24: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:1745:117: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2006:49: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2086:56: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2180:47: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2191:41: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2192:62: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2193:59: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2195:40: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2196:60: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2197:41: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2199:73: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2201:73: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2340:114: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:2392:47: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:3227:15: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:3381:29: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:3998:37: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:401:34: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:581:47: warning: potential null pointer dereference [-Wnull-dereference]
net_processing.cpp:653:33: warning: potential null pointer dereference [-Wnull-dereference]
rpc/mining.cpp:446:64: warning: potential null pointer dereference [-Wnull-dereference]
rpc/mining.cpp:500:30: warning: potential null pointer dereference [-Wnull-dereference]
test/miner_tests.cpp:371:35: warning: potential null pointer dereference [-Wnull-dereference]
test/miner_tests.cpp:383:35: warning: potential null pointer dereference [-Wnull-dereference]
test/miner_tests.cpp:414:35: warning: potential null pointer dereference [-Wnull-dereference]
test/miner_tests.cpp:445:110: warning: potential null pointer dereference [-Wnull-dereference]
test/miner_tests.cpp:458:110: warning: potential null pointer dereference [-Wnull-dereference]
test/validation_block_tests.cpp:322:67: warning: potential null pointer dereference [-Wnull-dereference]
txmempool.cpp:1027:55: warning: potential null pointer dereference [-Wnull-dereference]
txmempool.cpp:1027:87: warning: potential null pointer dereference [-Wnull-dereference]
validation.cpp:1453:24: warning: potential null pointer dereference [-Wnull-dereference]
validation.cpp:333:44: warning: potential null pointer dereference [-Wnull-dereference]
validation.cpp:387:85: warning: potential null pointer dereference [-Wnull-dereference]
validation.cpp:4416:102: warning: potential null pointer dereference [-Wnull-dereference]
wallet/db.cpp:32:19: warning: null pointer dereference [-Wnull-dereference]
wallet/test/wallet_tests.cpp:121:41: warning: potential null pointer dereference [-Wnull-dereference]
wallet/test/wallet_tests.cpp:41:41: warning: potential null pointer dereference [-Wnull-dereference]

@ryanofsky
Copy link
Contributor

If you want to continue working on making currently implicit != nullptr assumptions explicit you might want to try compiling with -Wnull-dereference to see what the compiler regards as potential null pointer dereferences.

I'm not sure there's much benefit to fixing these disabled warnings relative to the cost of implementing and reviewing the fixes. But there are going to be future PRs, another way of going about them instead of calling functions that return pointers and assert != nullptr at half the call sites, it can be better to write functions that return references and assert or throw internally.

bitcoin/src/wallet/wallet.h

Lines 761 to 762 in ddd4629

/** Interface for accessing chain state. */
interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }

static LegacyScriptPubKeyMan& GetLegacyScriptPubKeyMan(CWallet& wallet)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}

@maflcko
Copy link
Member

maflcko commented Nov 1, 2019

Hitting an assertion is always better than a segmentation fault, so while none of the -Wnull-dereference warnings are serious, it still makes sense to get rid of them in the long run. Either by replacing them with references where possible, as suggested by ryanofsky, or adding an assert where references are not applicable.

@adamjonas
Copy link
Member Author

I'm happy to follow up and keep working on these, but I'd prefer to open a separate PR(s) to address the other instances and maintain a low burden of review.

@DrahtBot
Copy link
Contributor

DrahtBot commented May 28, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

No conflicts as of last run.

Add sanity asserts for return value of `CBlockIndex::GetAncestor()` where appropriate.

In validation.cpp `CheckSequenceLocks`, check the return value of `tip->GetAncestor(maxInputHeight)` stored into `lp->maxInputBlock`. If it ever returns `nullptr` because the ancestor isn't found, it's going to be a bad bug to keep going, since a `LockPoints` object with the `maxInputBlock` member set to `nullptr` signifies no relative lock time.

In the other places, the added asserts would prevent accidental dereferencing of a null pointer which is undefined behavior.

Co-Authored-By: danra <danra@users.noreply.github.com>
@adamjonas
Copy link
Member Author

Going to close this for lack of interest. Maybe @MarcoFalke or @fanquake could label it up for grabs if someone wants to pick it back up again?

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, this PR fell off my radar.

Code review ACK b11df4a

A couple of completely ignorable nits if you re-open and have to retouch.

@@ -66,7 +66,9 @@ std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags
int nCoinHeight = prevHeights[txinIndex];

if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
const CBlockIndex* ancestor = block.GetAncestor(std::max(nCoinHeight-1, 0));
Copy link
Member

@jonatack jonatack Aug 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- const CBlockIndex* ancestor = block.GetAncestor(std::max(nCoinHeight-1, 0));
+ const CBlockIndex* ancestor = block.GetAncestor(std::max(nCoinHeight - 1, 0));

for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
// However if we advance height by 1 and time by SEQUENCE_LOCK_TIME, all of them should be mined
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
+ for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {

@practicalswift
Copy link
Contributor

@adamjonas Would you be willing to re-open this given renewed reviewer interest? :)

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants