validation: correct lifetime of precomputed tx data
What changed, and why it matters
This commit fixes a memory safety bug in Bitcoin Core's block validation. When checking a new block, the program creates a queue of script checks that may run on multiple threads in the background. It also precomputes some transaction data used by those checks. Previously, the precomputed data was destroyed before the background check queue finished, so the workers could read memory that had already been freed. An attacker could craft a malicious block to trigger this, potentially causing crashes, memory corruption, or worse. The fix simply moves the precomputed data variable so it is created before the queue and destroyed after it, guaranteeing the data stays alive as long as the checks need it.
Apply this reordering fix and ensure all supported release branches include it. Node operators should upgrade to a release containing this commit. Because the commit message states the vulnerability was already covertly fixed in 492e1f09943fcb6145c21d470299305a19e17d8b, verify whether this commit is a backport or a public disclosure follow-up and coordinate with the CVE-2024-52911 advisory for release notes and upgrade guidance.
Security signals we found
Use-after-free in block validation path
Lifetime/order-of-destruction bug between local objects
Exploitable by crafted invalid block
Remote, unauthenticated network-triggered memory corruption
CVE-2024-52911 referenced by vendor commit message
Earlier covert fix acknowledged in commit message
Evidence from the diff
In Chainstate::ConnectBlock, a CCheckQueueControl (background script-check queue) was constructed before the std::vector
Changed components
src/validation.cppChainstate::ConnectBlockCCheckQueueControl / script check queuePrecomputedTransactionData vectorInspect captured patch +1 / −2
diff --git a/src/validation.cpp b/src/validation.cpp
index f85a834f..211a8122 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2508,11 +2508,10 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// in multiple threads). Preallocate the vector size so a new allocation
// doesn't invalidate pointers into the vector, and keep txsdata in scope
// for as long as `control`.
+ std::vector<PrecomputedTransactionData> txsdata(block.vtx.size());
std::optional<CCheckQueueControl<CScriptCheck>> control;
if (auto& queue = m_chainman.GetCheckQueue(); queue.HasThreads() && fScriptChecks) control.emplace(queue);
- std::vector<PrecomputedTransactionData> txsdata(block.vtx.size());
-
std::vector<int> prevheights;
CAmount nFees = 0;
int nInputs = 0;
Why this scored 87/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.