summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-10-14 11:16:19 -0700
committerScott Gasch <[email protected]>2026-10-14 11:16:19 -0700
commitb3d4d0781faa189c74b05fec96814e3f30e449f9 (patch)
tree171b07d54a6a246ad2db958823c2a2d2d55e6b86
parent3845a082df2fd0d1bd059dd4c22c922067be826a (diff)
Fix iExtensionAmount write slot and staleness in HelpSearch()
HelpSearch()'s per-move loop wrote ctx->sPlyInfo[ctx->uPly] .iExtensionAmount after MakeMove had already advanced ctx->uPly, landing in the child's ply slot instead of the mover's own -- so a node one ply below a split-originated reduced move could never see that reduction via (pi-1)->iExtensionAmount (searchsup.c's null-move history-reduced-bailout check reads exactly that). Search()'s own move loop binds pi before MakeMove, so its equivalent write needs no adjustment; HelpSearch() needs the explicit -1 to land in the same place post-increment. Also only wrote the value when a move was actually reduced (iLMR < 0) rather than unconditionally every move -- the same staleness bug Search() itself used to have and already fixed (see its own comment at the unconditional write), where a later sibling move at the same ply could inherit a stale reduction value a different, earlier move left behind. Both fixes bring HelpSearch() in line with Search()'s already-correct convention: a single unconditional write to ctx->sPlyInfo[ctx->uPly - 1].iExtensionAmount after the reduction decision, for every move. Only reachable through a real split (multithreaded search), which is why this was easy to miss. Verified via precommit_check.sh (TEST=1 self-test suite + debug_smoke_test.sh), both pass. Co-Authored-By: Claude Sonnet 5 <[email protected]>
-rw-r--r--src/split.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/src/split.c b/src/split.c
index b019cde..e72bd2c 100644
--- a/src/split.c
+++ b/src/split.c
@@ -1242,10 +1242,21 @@ Return value:
{
ASSERT(iExtend == 0);
iExtend = iLMR;
- ctx->sPlyInfo[ctx->uPly].iExtensionAmount = iLMR;
}
}
+ // Record the extension/reduction actually applied to THIS
+ // move, unconditionally -- not just when it's negative.
+ // ctx->uPly - 1 (not ctx->uPly) because MakeMove above has
+ // already advanced ctx->uPly; the mover's own ply slot is
+ // one below the position it just produced. Matches
+ // search.c's identical convention/comment on its own
+ // pi->iExtensionAmount write (pi is bound pre-MakeMove
+ // there, so no -1 is needed in that file). Unconditional so
+ // a later sibling move at this split ply never inherits a
+ // stale reduction value left by an earlier one.
+ ctx->sPlyInfo[ctx->uPly - 1].iExtensionAmount = iExtend;
+
//
// Compute next depth
//
@@ -1265,7 +1276,7 @@ Return value:
if ((iExtend < 0) && (iScore >= iBeta))
{
uDepth -= iExtend; // undo the full reduction, whatever its magnitude
- ctx->sPlyInfo[ctx->uPly].iExtensionAmount = 0;
+ ctx->sPlyInfo[ctx->uPly - 1].iExtensionAmount = 0;
iScore = -Search(ctx, -iBeta, -iAlpha, uDepth);
}
UnmakeMove(ctx, mv);