diff options
| author | Scott Gasch <[email protected]> | 2026-10-14 11:44:16 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-10-14 11:44:16 -0700 |
| commit | 91f01c607338eabb10ae1f8c144be55071d174a5 (patch) | |
| tree | 89d14a9f6f6533152cad409095487f556ba3087f /tests/zugzwang.epd | |
| parent | b3d4d0781faa189c74b05fec96814e3f30e449f9 (diff) | |
Fix WouldGiveCheck race in StartParallelSearch's move snapshot
StartParallelSearch's snapshot loop (split.c, the move list handed to
helper threads at a split) skipped recomputing WouldGiveCheck for
v == uMoveNum on the assumption that Search()'s own loop had already
computed it moments earlier when it originally selected that move.
That assumption only holds if re-running SelectBestWithHistory(ctx,
uMoveNum) is a no-op. It isn't: the loop calls SelectBestWithHistory
for every v including uMoveNum, which rescans [v, uEnd) using
g_HistoryCounters/g_ContinuationHistory -- process-global state
written by every other searcher thread with no lock. Between
Search()'s original selection and this second one a few lines later,
another thread can mutate those tables enough to change which move
wins the scan, swapping a *different* move into slot uMoveNum than
the one originally selected -- one whose check bit was never
computed, inheriting a stale/garbage value instead.
That move, with its wrong check bit, got handed to a helper thread via
g_SplitInfo[u].mvf[], tripping HelpSearch's own
IS_CHECKING_MOVE/InCheck invariant (visible as "Assertion failure in
split.c, line 1143" under DEBUG) or, in a release build, corrupting
move generation further down the line (observed as "Typhoon PANIC 0x4
... Location: generate.c" via InvalidGenerator, when a move wrongly
believed non-checking reached a dispatch table expecting the opposite
invariant).
Confirmed via a DEBUG=1 build at --cpus 4: reliably reproduced within
the first ~15 positions of ecm_confident_quick at sd10 before this fix
(same assert, different positions across repeated runs -- consistent
with a real race, not a deterministic bug), and ran 43 consecutive
positions with zero assertion failures after. Also confirmed
pre-existing at HEAD~2 (3d54c2c, before this session's prior two
commits), so unrelated to the search-unification work in progress.
Fix: always recompute WouldGiveCheck for every move in this loop,
including uMoveNum. This loop runs once per split (not once per move
tried), so the extra call is split overhead, not a per-node cost.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'tests/zugzwang.epd')
0 files changed, 0 insertions, 0 deletions
