mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Improve CLI error handling a bit
Reduce the number of *easy* ways to hit UB or an uncaught exception. This builds on Sopel's work on FEN validation. Obviously SF is not and will never be a security boundary, but at least we can reduce the number of reports about uncaught `std::stoi` out of range, etc. I also added a gentle fallback to `NumaConfig` specifically because that's something that (as a dev) I frequently set by hand in the CLI, but happy to revert if that's too annoying of a change. closes https://github.com/official-stockfish/Stockfish/pull/6844 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
48a9118251
commit
cd75d31127
+26
-8
@@ -28,6 +28,7 @@
|
||||
#include <string_view>
|
||||
#include <filesystem>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark.h"
|
||||
@@ -98,6 +99,7 @@ void UCIEngine::loop() {
|
||||
&& !getline(std::cin, cmd)) // Wait for an input or an end-of-file (EOF) indication
|
||||
cmd = "quit";
|
||||
|
||||
currentCmd = cmd;
|
||||
std::istringstream is(cmd);
|
||||
|
||||
token.clear(); // Avoid a stale if getline() returns nothing or a blank line
|
||||
@@ -138,9 +140,13 @@ void UCIEngine::loop() {
|
||||
sync_cout << "readyok" << sync_endl;
|
||||
|
||||
// Add custom non-UCI commands, mainly for debugging purposes.
|
||||
// These commands must not be used during a search!
|
||||
else if (token == "flip")
|
||||
engine.flip();
|
||||
{
|
||||
if (auto err = engine.flip())
|
||||
{
|
||||
terminate_on_critical_error(err->what());
|
||||
}
|
||||
}
|
||||
else if (token == "bench")
|
||||
bench(is);
|
||||
else if (token == BenchmarkCommand)
|
||||
@@ -184,9 +190,13 @@ Search::LimitsType UCIEngine::parse_limits(std::istream& is) {
|
||||
limits.startTime = now(); // The search starts as early as possible
|
||||
|
||||
while (is >> token)
|
||||
{
|
||||
if (token == "searchmoves") // Needs to be the last command on the line
|
||||
{
|
||||
while (is >> token)
|
||||
limits.searchmoves.push_back(to_lower(token));
|
||||
break;
|
||||
}
|
||||
|
||||
else if (token == "wtime")
|
||||
is >> limits.time[WHITE];
|
||||
@@ -213,6 +223,10 @@ Search::LimitsType UCIEngine::parse_limits(std::istream& is) {
|
||||
else if (token == "ponder")
|
||||
limits.ponderMode = true;
|
||||
|
||||
if (is.fail())
|
||||
terminate_on_critical_error("Invalid argument for '" + token + "'");
|
||||
}
|
||||
|
||||
return limits;
|
||||
}
|
||||
|
||||
@@ -459,7 +473,11 @@ void UCIEngine::setoption(std::istringstream& is) {
|
||||
}
|
||||
|
||||
u64 UCIEngine::perft(const Search::LimitsType& limits) {
|
||||
auto nodes = engine.perft(engine.fen(), limits.perft, engine.get_options()["UCI_Chess960"]);
|
||||
auto result = engine.perft(engine.fen(), limits.perft, engine.get_options()["UCI_Chess960"]);
|
||||
if (auto err = std::get_if<PositionSetError>(&result))
|
||||
terminate_on_critical_error(err->what());
|
||||
|
||||
auto nodes = std::get<u64>(result);
|
||||
sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
|
||||
return nodes;
|
||||
}
|
||||
@@ -492,7 +510,7 @@ void UCIEngine::position(std::istringstream& is) {
|
||||
auto err = engine.set_position(fen, moves);
|
||||
if (err.has_value())
|
||||
{
|
||||
terminate_on_critical_error(fullCommand, err->what());
|
||||
terminate_on_critical_error(err->what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,7 +618,8 @@ std::string UCIEngine::move(Move m, bool chess960) {
|
||||
|
||||
|
||||
std::string UCIEngine::to_lower(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](auto c) { return std::tolower(c); });
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -662,9 +681,8 @@ void UCIEngine::on_bestmove(std::string_view bestmove, std::string_view ponder)
|
||||
std::cout << sync_endl;
|
||||
}
|
||||
|
||||
void UCIEngine::terminate_on_critical_error(const std::string& fullCommand,
|
||||
const std::string& message) {
|
||||
sync_cout << "info string CRITICAL ERROR: Command `" << fullCommand
|
||||
void UCIEngine::terminate_on_critical_error(const std::string& message) {
|
||||
sync_cout << "info string CRITICAL ERROR: Command `" << currentCmd
|
||||
<< "` failed. Reason: " << message << '\n'
|
||||
<< sync_endl;
|
||||
std::exit(1);
|
||||
|
||||
Reference in New Issue
Block a user