ref: d468ffc53681ee75056f8a99657c3cf11491db75
parent: 608575ebb95f78761a5c010dd2e7f3c77202e64e
author: zamfofex <zamfofex@twdb.moe>
date: Wed May 8 10:59:09 EDT 2024
fix UCI move name parsing
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@
- the TUIs do not let you underpromote
- no transposition table
- no support for `go infinite`, `go mate`, or `go nodes`
-- no move name or FEN validation (may lead to potential exploits)
+- no FEN validation (may lead to potential exploits)
download
---
--- a/chess.c
+++ b/chess.c
@@ -374,12 +374,22 @@
}
}
-void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name)
+int moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name)
{int x0, y0;
int x1, y1;
- unsigned char piece;
+ unsigned char piece, color;
+ unsigned char from, to;
+ int i, count;
+ struct moonfish_move moves[32];
+#ifndef moonfish_mini
+ if (name[0] < 'a' || name[0] > 'h') return 1;
+ if (name[1] < '1' || name[1] > '8') return 1;
+ if (name[2] < 'a' || name[2] > 'h') return 1;
+ if (name[3] < '1' || name[3] > '8') return 1;
+#endif
+
x0 = name[0] - 'a';
y0 = name[1] - '1';
x1 = name[2] - 'a';
@@ -392,12 +402,42 @@
if (x1 == 7) x1 = 6;
}
- if (name[4] == 'q') piece = moonfish_queen;
- if (name[4] == 'r') piece = moonfish_rook;
- if (name[4] == 'b') piece = moonfish_bishop;
- if (name[4] == 'n') piece = moonfish_knight;
+ color = piece & 0xF0;
- moonfish_force_promotion(chess, &move, (x0 + 1) + (y0 + 2) * 10, (x1 + 1) + (y1 + 2) * 10, piece);
+ switch (name[4])
+ {+ default:
+ return 1;
+ case 0:
+ break;
+ case 'q':
+ piece = color | moonfish_queen;
+ break;
+ case 'r':
+ piece = color | moonfish_rook;
+ break;
+ case 'b':
+ piece = color | moonfish_bishop;
+ break;
+ case 'n':
+ piece = color | moonfish_knight;
+ break;
+ }
+
+ from = (x0 + 1) + (y0 + 2) * 10;
+ to = (x1 + 1) + (y1 + 2) * 10;
+
+ count = moonfish_moves(chess, moves, from);
+
+ for (i = 0 ; i < count ; i++)
+ {+ if (moves[i].to != to) continue;
+ if (moves[i].chess.board[to] != piece) continue;
+ *move = moves[i];
+ return 0;
+ }
+
+ return 1;
}
void moonfish_to_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name)
--- a/main.c
+++ b/main.c
@@ -211,7 +211,11 @@
{while ((arg = strtok(NULL, "\r\n\t ")) != NULL)
{- moonfish_from_uci(&chess, &move, arg);
+ if (moonfish_from_uci(&chess, &move, arg))
+ {+ fprintf(stderr, "%s: invalid move '%s'\n", argv[0], arg);
+ return 1;
+ }
chess = move.chess;
}
}
--- a/moonfish.h
+++ b/moonfish.h
@@ -169,8 +169,9 @@
/* creates a move from UCI notation */
/* the move is stored in "move" */
-/* the given move it is not validated! (so make sure the move is actually valid) */
-void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
+/* on success, the parser will return 0, on failure, it will return 1 (and the move is unusable) */
+/* parsing is somewhat robust, so you can trust it won't succeed with an invalid move */
+int moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
/* converts a move to UCI notation */
/* the name is stored in the given "char" pointer (including the trailing NUL), so make sure you pass in a pointer that can fit it */
@@ -203,7 +204,7 @@
/* similar to "moonfish_from_uci" and "moonfish_to_uci", but for SAN instead */
/* SAN parsing is very loose, so it will accept many forms, including UCI */
-/* on succes, SAN parsing will return 0, on failure, it will return 1 (and the move is unchanged) */
+/* on success, the parser will return 0, on failure, it will return 1 (and the move is unusable) */
/* parsing is somewhat robust, so you can trust it won't succeed with an invalid move */
int moonfish_from_san(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
void moonfish_to_san(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
--- a/tools/battle.c
+++ b/tools/battle.c
@@ -308,7 +308,12 @@
battle->moves[battle->move_count++] = arg;
if (!battle->ugi)
{- moonfish_from_uci(&battle->chess, &move, arg);
+ if (moonfish_from_uci(&battle->chess, &move, arg))
+ {+ fprintf(stderr, "%s: invalid move '%s' from the bot\n", argv0, arg);
+ exit(1);
+ }
+
battle->chess = move.chess;
}
--- a/tools/chat.c
+++ b/tools/chat.c
@@ -302,7 +302,12 @@
strcat(names, " ");
strcat(names, name0);
- moonfish_from_uci(&chess, &move, name0);
+ if (moonfish_from_uci(&chess, &move, name0))
+ {+ fprintf(stderr, "%s: invalid move '%s' by the bot\n", argv0, name0);
+ exit(1);
+ }
+
moonfish_to_san(&chess, &move, name);
chess = move.chess;
moonfish_to_fen(&chess, fen);
--- a/tools/lichess.c
+++ b/tools/lichess.c
@@ -187,7 +187,12 @@
name = strtok(moves->valuestring, " ");
for (;;)
{- moonfish_from_uci(&chess, &move, name);
+ if (moonfish_from_uci(&chess, &move, name))
+ {+ fprintf(stderr, "%s: invalid move '%s' from the bot\n", game->argv0, name);
+ exit(1);
+ }
+
moonfish_to_uci(&chess, &move, name0);
fprintf(in, "%s", name0);
name = strtok(NULL, " ");
@@ -222,13 +227,21 @@
if (variant)
{- moonfish_from_uci(&chess, &move, name);
- if (chess.board[move.from] % 16 == moonfish_king)
+ if (chess.board[25] == moonfish_white_king)
{if (!strcmp(name, "e1c1")) name = "e1a1";
- else if (!strcmp(name, "e1g1")) name = "e1h1";
- else if (!strcmp(name, "e8c8")) name = "e8a8";
- else if (!strcmp(name, "e8g8")) name = "e8h8";
+ if (!strcmp(name, "e1g1")) name = "e1h1";
+ }
+ if (chess.board[25] % 16 == moonfish_black_king)
+ {+ if (!strcmp(name, "e8c8")) name = "e8a8";
+ if (!strcmp(name, "e8g8")) name = "e8h8";
+ }
+
+ if (moonfish_from_uci(&chess, &move, name))
+ {+ fprintf(stderr, "%s: invalid move '%s' from the bot\n", game->argv0, name);
+ exit(1);
}
}
--- a/tools/play.c
+++ b/tools/play.c
@@ -281,7 +281,13 @@
strcpy(name, arg);
pthread_mutex_lock(fancy->mutex);
- moonfish_from_uci(&fancy->chess, &move, arg);
+
+ if (moonfish_from_uci(&fancy->chess, &move, arg))
+ {+ fprintf(stderr, "%s: invalid move '%s' from the bot\n", fancy->argv0, arg);
+ exit(1);
+ }
+
fancy->chess = move.chess;
}
--- a/tools/ugi-uci.c
+++ b/tools/ugi-uci.c
@@ -166,7 +166,11 @@
{arg = strtok_r(NULL, " ", &save);
if (arg == NULL) break;
- moonfish_from_uci(&moonfish_ugi_chess, &move, arg);
+ if (moonfish_from_uci(&moonfish_ugi_chess, &move, arg))
+ {+ fprintf(stderr, "%s: invalid move '%s' from bot\n", moonfish_argv0, arg);
+ exit(1);
+ }
moonfish_ugi_chess = move.chess;
}
}
--
⑨