1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-30 08:43:09 +00:00
BadFish/src/tt.cpp
Marco Costalba 6442981cb6 Fix an hang on 32 bits while allocating big TT table
If size_t is defined as a 32 bit quanitity then we have an
overflow in the left term of the while condition if mbSize
is bigger then 2048.

For instance if mbSize is 2049 then when newSize will reach
0x80000000 (2048MB) comparison is still true, 'while' loops
again and we have an overflow in the expression (2*newSize)
so that result is 0 and at that point 'while' keeps looping
forever hanging the application.

This patch fixes the bug and also makes operator new do not
throw an exception upon failure but return a NULL pointer
instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-13 22:03:18 +01:00

159 lines
4.6 KiB
C++

/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include <cstring>
#include <iostream>
#include "tt.h"
// The main transposition table
TranspositionTable TT;
////
//// Functions
////
TranspositionTable::TranspositionTable() {
size = 0;
entries = 0;
generation = 0;
}
TranspositionTable::~TranspositionTable() {
delete [] entries;
}
/// TranspositionTable::set_size sets the size of the transposition table,
/// measured in megabytes.
void TranspositionTable::set_size(size_t mbSize) {
size_t newSize = 1024;
// Transposition table consists of clusters and each cluster consists
// of ClusterSize number of TTEntries. Each non-empty entry contains
// information of exactly one position and newSize is the number of
// clusters we are going to allocate.
while (2ULL * newSize * sizeof(TTCluster) <= (mbSize << 20))
newSize *= 2;
if (newSize != size)
{
size = newSize;
delete [] entries;
entries = new (std::nothrow) TTCluster[size];
if (!entries)
{
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
exit(EXIT_FAILURE);
}
clear();
}
}
/// TranspositionTable::clear overwrites the entire transposition table
/// with zeroes. It is called whenever the table is resized, or when the
/// user asks the program to clear the table (from the UCI interface).
/// Perhaps we should also clear it when the "ucinewgame" command is received?
void TranspositionTable::clear() {
memset(entries, 0, size * sizeof(TTCluster));
}
/// TranspositionTable::store writes a new entry containing position key and
/// valuable information of current position.
/// The Lowest order bits of position key are used to decide on which cluster
/// the position will be placed.
/// When a new entry is written and there are no empty entries available in cluster,
/// it replaces the least valuable of entries.
/// A TTEntry t1 is considered to be more valuable than a TTEntry t2 if t1 is from the
/// current search and t2 is from a previous search, or if the depth of t1
/// is bigger than the depth of t2.
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m, Value statV, Value kingD) {
int c1, c2, c3;
TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
tte = replace = first_entry(posKey);
for (int i = 0; i < ClusterSize; i++, tte++)
{
if (!tte->key() || tte->key() == posKey32) // empty or overwrite old
{
// Preserve any existing ttMove
if (m == MOVE_NONE)
m = tte->move();
tte->save(posKey32, v, t, d, m, generation, statV, kingD);
return;
}
if (i == 0) // Replacing first entry is default and already set before entering for-loop
continue;
c1 = (replace->generation() == generation ? 2 : 0);
c2 = (tte->generation() == generation ? -2 : 0);
c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0)
replace = tte;
}
replace->save(posKey32, v, t, d, m, generation, statV, kingD);
}
/// TranspositionTable::retrieve looks up the current position in the
/// transposition table. Returns a pointer to the TTEntry or NULL
/// if position is not found.
TTEntry* TranspositionTable::retrieve(const Key posKey) const {
uint32_t posKey32 = posKey >> 32;
TTEntry* tte = first_entry(posKey);
for (int i = 0; i < ClusterSize; i++, tte++)
if (tte->key() == posKey32)
return tte;
return NULL;
}
/// TranspositionTable::new_search() is called at the beginning of every new
/// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from
/// entries from the current search.
void TranspositionTable::new_search() {
generation++;
}