AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Moderate 57 Bitcoin

validation: fix UB in LoadChainTip

Public commit record

What the developer wrote

Authored by marcofleon

68/100 · Adequate
validation: fix UB in LoadChainTip

The removal of the chain tip from setBlockIndexCandidates was
happening after nSequenceId was modified. Since the set uses
nSequenceId as a sort key, modifying it while the element is in the
set is undefined behavior, which can cause the erase to fail.

With assumeutxo, a second form of UB exists: two chainstates each
have their own candidate set, but share the same CBlockIndex
objects. Calling LoadChainTip on one chainstate mutates nSequenceIds
that are also in the other chainstate's set.

Fix by populating setBlockIndexCandidates after all changes to
nSequenceId.
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
The short version

What changed, and why it matters

This commit fixes a low-level memory-handling bug in Bitcoin Core's startup code. When loading the chain tip, the program was changing a value (nSequenceId) that is also used to sort a set of candidate blocks, while the block was still in that set. In C++, changing a sort key while an item is in a sorted set is 'undefined behavior'—the program may crash, corrupt data, or behave unpredictably. The fix moves the population of the candidate set to after all such changes are complete. A second, related problem existed with the experimental assumeutxo feature, where two separate chain states share the same block objects and could interfere with each other's candidate sets. The patch addresses both by clearing and repopulating candidate sets at safe points.

Recommended action

Treat this as a stability and potential consensus-adjacent correctness fix. It should be backported to maintained release branches, especially those supporting assumeutxo. Node operators should upgrade. Reviewers should verify that all call sites that previously populated setBlockIndexCandidates now do so via PopulateBlockIndexCandidates after any nSequenceId changes, and that no new paths mutate nSequenceId while candidates are present.

Security signals we found

01

Undefined behavior due to modifying a std::set sort key while the element is in the set

02

Shared mutable CBlockIndex state across multiple Chainstates under assumeutxo

03

Potential failure to erase the chain tip from the candidate set, leading to stale or inconsistent best-chain selection

04

Assertion added to enforce empty candidate sets before nSequenceId mutation

05

Refactoring of candidate-set lifecycle to separate mutation from population

Risk score

Why this scored 57/100

Our methodology →
Potential impact 18/30
Exploitability 8/25
Stealth signal 10/15
Affected reach 10/15
Confidence 7/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.