mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Fix crash with UCI_LimitStrength and tablebases at the root
`Skill::pick_best()` assumes the root moves are sorted by score in descending order:
```cpp
Value topScore = rootMoves[0].score;
int delta = std::min(topScore - rootMoves[multiPV - 1].score, int(PawnValue));
```
That does not have to be so with Syzygy tablebases at the root, where the moves are ordered by `tbRank` instead. `rootMoves[0]` is then not the highest score and `delta` can go negative. Since `delta * (rng.rand<unsigned>() % int(weakness))` is evaluated as unsigned, a negative `delta` wraps to a large value and the `int(...)` cast overflows, so the `score + push >= maxScore` check never passes and `best` stays `Move::none()`. The caller
```cpp
std::swap(rootMoves[0],
*std::find(rootMoves.begin(), rootMoves.end(),
skill.best ? skill.best : skill.pick_best(rootMoves, multiPV)));
```
then dereferences `end()`. The result is a crash, or sometimes `bestmove (none)` / an illegal move, in tablebase endgames when `UCI_LimitStrength` is set (or `Skill Level` is below 20).
The fix computes the score range over the candidate moves directly, so `delta` stays non-negative and a valid move is always returned.
**To reproduce**:
```
setoption name UCI_LimitStrength value true
setoption name UCI_Elo value 2900
setoption name SyzygyPath value <syzygy tablebases path>
position fen 8/8/8/4k3/8/8/3BKN2/8 b - - 0 1
go wtime 250 btime 250 winc 100 binc 100
```
You need to call the go command a couple of times before crash, after which is ends with
```
bestmove a1e5 ponder (none)
```
and on the next `go wtime 250 btime 250 winc 100 binc 100` it crashes printing:
```
info string Available processors: 0-31
info string Using 1 thread
info string NNUE evaluation using nn-af1339a6dea3.nnue (106MiB, (83248, 1024, 31, 32, 1))
info string Network replica 1: Shared memory.
```
Bench is unchanged, since this code only runs under `UCI_LimitStrength` / `Skill Level`.
closes https://github.com/official-stockfish/Stockfish/pull/6957
No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
2d239de460
commit
9700f6f206
@@ -180,6 +180,7 @@ Michel Van den Bergh (vdbergh)
|
||||
Miguel Lahoz (miguel-l)
|
||||
Mikael Bäckman (mbootsector)
|
||||
Mike Babigian (Farseer)
|
||||
Miloslav Macůrek (maelic13)
|
||||
Mira
|
||||
Miroslav Fontán (Hexik)
|
||||
Moez Jellouli (MJZ1977)
|
||||
|
||||
+9
-2
@@ -2005,9 +2005,16 @@ void update_quiet_histories(
|
||||
Move Skill::pick_best(const RootMoves& rootMoves, usize multiPV) {
|
||||
static PRNG rng(now()); // PRNG sequence should be non-deterministic
|
||||
|
||||
// RootMoves are already sorted by score in descending order
|
||||
// With tablebases at the root, rootMoves are ordered by tbRank rather than by
|
||||
// score, so compute the score range explicitly to keep 'delta' non-negative.
|
||||
Value topScore = rootMoves[0].score;
|
||||
int delta = std::min(topScore - rootMoves[multiPV - 1].score, int(PawnValue));
|
||||
Value minScore = rootMoves[0].score;
|
||||
for (usize i = 1; i < multiPV; ++i)
|
||||
{
|
||||
topScore = std::max(topScore, rootMoves[i].score);
|
||||
minScore = std::min(minScore, rootMoves[i].score);
|
||||
}
|
||||
int delta = std::min(topScore - minScore, int(PawnValue));
|
||||
int maxScore = -VALUE_INFINITE;
|
||||
double weakness = 120 - 2 * level;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user