shithub: moonfish

Download patch

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;
 				}
 			}
--