Since the hash move may change from other threads while we're looking at it,
we could end up applying illegal moves when recovering the PV, corrupting the
state and causing out-of-bounds accesses.
Spotted by vondele.
TTEntry *entry = TT.probe(pos->key(), found);
response->set_found(found);
if (found) {
TTEntry *entry = TT.probe(pos->key(), found);
response->set_found(found);
if (found) {
- Value value = entry->value();
- Value eval = entry->eval();
- Bound bound = entry->bound();
+ TTEntry entry_copy = *entry;
+ Value value = entry_copy.value();
+ Value eval = entry_copy.eval();
+ Bound bound = entry_copy.bound();
if (invert) {
value = -value;
if (invert) {
value = -value;
- response->set_depth(entry->depth());
+ response->set_depth(entry_copy.depth());
FillValue(eval, response->mutable_eval());
FillValue(eval, response->mutable_eval());
- if (entry->depth() > DEPTH_NONE) {
+ if (entry_copy.depth() > DEPTH_NONE) {
FillValue(value, response->mutable_value());
}
response->set_bound(HashProbeLine::ValueBound(bound));
FillValue(value, response->mutable_value());
}
response->set_bound(HashProbeLine::ValueBound(bound));
// Follow the PV until we hit an illegal move.
std::stack<Move> pv;
std::set<Key> seen;
// Follow the PV until we hit an illegal move.
std::stack<Move> pv;
std::set<Key> seen;
- while (found && is_ok(entry->move()) &&
- pos->pseudo_legal(entry->move()) &&
- pos->legal(entry->move())) {
- FillMove(pos, entry->move(), response->add_pv());
+ while (is_ok(entry_copy.move()) &&
+ pos->pseudo_legal(entry_copy.move()) &&
+ pos->legal(entry_copy.move())) {
+ FillMove(pos, entry_copy.move(), response->add_pv());
if (seen.count(pos->key())) break;
if (seen.count(pos->key())) break;
- pv.push(entry->move());
+ pv.push(entry_copy.move());
seen.insert(pos->key());
setup_states->push_back(StateInfo());
seen.insert(pos->key());
setup_states->push_back(StateInfo());
- pos->do_move(entry->move(), setup_states->back());
+ pos->do_move(entry_copy.move(), setup_states->back());
entry = TT.probe(pos->key(), found);
entry = TT.probe(pos->key(), found);
+ if (!found) {
+ break;
+ }
+ entry_copy = *entry;
}
// Unroll the PV back again, so the Position object remains unchanged.
}
// Unroll the PV back again, so the Position object remains unchanged.