fix: guard BuildWitnessCache against an off-active-chain pindex (heap overflow)
BuildWitnessCache sizes its blockCms buffer from pindex->GetHeight() but the Phase-1 loop walks the active chain (chainActive.Next), terminating only on pbi==pindex. If a reorg moved pindex off the active chain while the notify thread lagged (cs_main is released between per-block ChainTip calls) and the new active tip is taller, the loop never reaches pindex and, once past pindex's height, writes blockCms[h-startHeight] out of bounds -- a heap overflow. Rebuilding witnesses for an abandoned block is meaningless anyway, so bail early when pindex is not on the active chain; cs_main is held for the whole function, so the check cannot race the loop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1229,6 +1229,20 @@ void CWallet::BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly)
|
|||||||
|
|
||||||
LOCK2(cs_main, cs_wallet);
|
LOCK2(cs_main, cs_wallet);
|
||||||
|
|
||||||
|
// The Phase-1 loop below walks the ACTIVE chain (chainActive.Next) and sizes blockCms from
|
||||||
|
// pindex->GetHeight(), terminating only on pbi==pindex. If pindex was reorged OFF the active
|
||||||
|
// chain (a reorg landed while ThreadNotifyWallets drained its connect backlog with cs_main
|
||||||
|
// released), the loop never reaches pindex and, once the active tip passes pindex's height, it
|
||||||
|
// writes blockCms[h-startHeight] out of bounds -> heap overflow. Rebuilding witnesses for an
|
||||||
|
// abandoned block is meaningless; the ChainTip for the new active tip re-drives this. cs_main is
|
||||||
|
// held for the whole function, so this check cannot race the loop below.
|
||||||
|
if (pindex != chainActive[pindex->GetHeight()]) {
|
||||||
|
if (fZdebug)
|
||||||
|
LogPrintf("%s: pindex height=%d not on active chain (reorg); skipping witness rebuild\n",
|
||||||
|
__func__, pindex->GetHeight());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int startHeight = VerifyAndSetInitialWitness(pindex, witnessOnly) + 1;
|
int startHeight = VerifyAndSetInitialWitness(pindex, witnessOnly) + 1;
|
||||||
|
|
||||||
if (startHeight > pindex->GetHeight() || witnessOnly) {
|
if (startHeight > pindex->GetHeight() || witnessOnly) {
|
||||||
|
|||||||
Reference in New Issue
Block a user