]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Fix asserts due to TT access races
[stockfish] / src / search.cpp
index b43ebd02ab848ae4f2675bd0eaba637b8f9532b8..f82197f87286f83b678b593d8526b479235c9325 100644 (file)
@@ -524,7 +524,7 @@ namespace {
     if (!RootNode)
     {
         // Step 2. Check for aborted search and immediate draw
-        if (Signals.stop || pos.is_draw<false>() || ss->ply > MAX_PLY)
+        if (Signals.stop || pos.is_draw<true, PvNode>() || ss->ply > MAX_PLY)
             return DrawValue[pos.side_to_move()];
 
         // Step 3. Mate distance pruning. Even if we mate at the next move our score
@@ -553,13 +553,13 @@ namespace {
     // smooth experience in analysis mode. We don't probe at Root nodes otherwise
     // we should also update RootMoveList to avoid bogus output.
     if (   !RootNode
-        && tte && tte->depth() >= depth
+        && tte
+        && tte->depth() >= depth
+        && ttValue != VALUE_NONE // Only in case of TT access race
         && (           PvNode ?  tte->type() == BOUND_EXACT
             : ttValue >= beta ? (tte->type() & BOUND_LOWER)
                               : (tte->type() & BOUND_UPPER)))
     {
-        assert(ttValue != VALUE_NONE); // Due to depth > DEPTH_NONE
-
         TT.refresh(tte);
         ss->currentMove = ttMove; // Can be MOVE_NONE
 
@@ -580,16 +580,22 @@ namespace {
 
     else if (tte)
     {
-        assert(tte->static_value() != VALUE_NONE);
-        assert(ttValue != VALUE_NONE || tte->type() == BOUND_NONE);
+        // Following asserts are valid only in single thread condition because
+        // TT access is always racy and its contents cannot be trusted.
+        assert(tte->static_value() != VALUE_NONE || Threads.size() > 1);
+        assert(ttValue != VALUE_NONE || tte->type() == BOUND_NONE || Threads.size() > 1);
 
         ss->staticEval = eval = tte->static_value();
         ss->evalMargin = tte->static_value_margin();
 
+        if (eval == VALUE_NONE || ss->evalMargin == VALUE_NONE) // Due to a race
+            eval = ss->staticEval = evaluate(pos, ss->evalMargin);
+
         // Can ttValue be used as a better position evaluation?
-        if (   ((tte->type() & BOUND_LOWER) && ttValue > eval)
-            || ((tte->type() & BOUND_UPPER) && ttValue < eval))
-            eval = ttValue;
+        if (ttValue != VALUE_NONE)
+            if (   ((tte->type() & BOUND_LOWER) && ttValue > eval)
+                || ((tte->type() & BOUND_UPPER) && ttValue < eval))
+                eval = ttValue;
     }
     else
     {
@@ -958,7 +964,7 @@ split_point_start: // At split points actual search starts from here
       // ran out of time. In this case, the return value of the search cannot
       // be trusted, and we don't update the best move and/or PV.
       if (Signals.stop || thisThread->cutoff_occurred())
-          return bestValue;
+          return value; // To avoid returning VALUE_INFINITE
 
       if (RootNode)
       {
@@ -1103,7 +1109,7 @@ split_point_start: // At split points actual search starts from here
     ss->ply = (ss-1)->ply + 1;
 
     // Check for an instant draw or maximum ply reached
-    if (pos.is_draw<true>() || ss->ply > MAX_PLY)
+    if (pos.is_draw<false, false>() || ss->ply > MAX_PLY)
         return DrawValue[pos.side_to_move()];
 
     // Transposition table lookup. At PV nodes, we don't use the TT for
@@ -1118,13 +1124,13 @@ split_point_start: // At split points actual search starts from here
     // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
     ttDepth = inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
                                                   : DEPTH_QS_NO_CHECKS;
-    if (   tte && tte->depth() >= ttDepth
+    if (   tte
+        && tte->depth() >= ttDepth
+        && ttValue != VALUE_NONE // Only in case of TT access race
         && (           PvNode ?  tte->type() == BOUND_EXACT
             : ttValue >= beta ? (tte->type() & BOUND_LOWER)
                               : (tte->type() & BOUND_UPPER)))
     {
-        assert(ttValue != VALUE_NONE); // Due to ttDepth > DEPTH_NONE
-
         ss->currentMove = ttMove; // Can be MOVE_NONE
         return ttValue;
     }
@@ -1140,10 +1146,13 @@ split_point_start: // At split points actual search starts from here
     {
         if (tte)
         {
-            assert(tte->static_value() != VALUE_NONE);
+            assert(tte->static_value() != VALUE_NONE || Threads.size() > 1);
 
             ss->staticEval = bestValue = tte->static_value();
             ss->evalMargin = tte->static_value_margin();
+
+            if (ss->staticEval == VALUE_NONE || ss->evalMargin == VALUE_NONE) // Due to a race
+                ss->staticEval = bestValue = evaluate(pos, ss->evalMargin);
         }
         else
             ss->staticEval = bestValue = evaluate(pos, ss->evalMargin);
@@ -1552,7 +1561,7 @@ void RootMove::extract_pv_from_tt(Position& pos) {
          && pos.is_pseudo_legal(m)
          && pos.pl_move_is_legal(m, pos.pinned_pieces())
          && ply < MAX_PLY
-         && (!pos.is_draw<false>() || ply < 2))
+         && (!pos.is_draw<true, true>() || ply < 2))
   {
       pv.push_back(m);
       pos.do_move(m, *st++);