[PATCH 1/2] Fix handling of empty move string.
[email protected] Mon, 7 Jul 2025 09:40:52 -0400
| Newsgroups | gmane.comp.gnu.chess.bugs |
|---|---|
| Message-ID | <[email protected]> |
From: Rudolf Polzer <[email protected]> Fixes read underflow at `mvstr[-1]` when the move string is empty: ``` $ CXXFLAGS='-O1 -g3 -fsanitize=address' LDFLAGS='-g3 -fsanitize=address' ./configure $ make -j4 $ src/gnuchess GNU Chess Can't open file "(null)": Bad address - using defaults White (1) : ``` Here, just hit Enter: ``` ================================================================= ==2615519==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7fed51b0011f at pc 0x55ecf95ce8ac bp 0x7ffe8f10ac20 sp 0x7ffe8f10ac18 READ of size 1 at 0x7fed51b0011f thread T0 #0 0x55ecf95ce8ab in ValidateMove(char*, char*) /home/rpolzer/src/gnuchess/src/frontend/move.cc:567 #1 0x55ecf95b945a in parse_input() /home/rpolzer/src/gnuchess/src/frontend/cmd.cc:1337 #2 0x55ecf95d608d in NextUserCmd() /home/rpolzer/src/gnuchess/src/frontend/engine.cc:267 #3 0x55ecf95b4694 in main /home/rpolzer/src/gnuchess/src/main.cc:503 #4 0x7fed53a33ca7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #5 0x7fed53a33d64 in __libc_start_main_impl ../csu/libc-start.c:360 #6 0x55ecf95b38e0 in _start (/home/rpolzer/homedir/src/gnuchess/src/gnuchess+0x278e0) (BuildId: b1b59d825678eda5d98b232e262b6913e2b55ec4) Address 0x7fed51b0011f is located in stack of thread T0 at offset 31 in frame #0 0x55ecf95ce72c in ValidateMove(char*, char*) /home/rpolzer/src/gnuchess/src/frontend/move.cc:537 This frame has 1 object(s): [32, 160) 'mvstr' (line 541) <== Memory access at offset 31 underflows this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-underflow /home/rpolzer/src/gnuchess/src/frontend/move.cc:567 in ValidateMove(char*, char*) Shadow bytes around the buggy address: 0x7fed51affe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51afff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51afff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51b00000: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51b00080: 00 00 00 00 f3 f3 f3 f3 00 00 00 00 00 00 00 00 =>0x7fed51b00100: f1 f1 f1[f1]00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51b00180: 00 00 00 00 f3 f3 f3 f3 00 00 00 00 00 00 00 00 0x7fed51b00200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51b00280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51b00300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7fed51b00380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==2615519==ABORTING ``` Also, could remove removal of +#= suffixes - the very thing crashing - by simply already removing the characters in the preceding copy loop (was already the case for all except #). Hope that's OK - the main difference is that now `#e2e4` is read as a valid move, and not as an error. If that is not OK and `#` was intended as a comment character, can revise (should then also skip the line and not show "Invalid move: #e2e4", though). --- src/frontend/move.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/frontend/move.cc b/src/frontend/move.cc index 3163166..6904e08 100644 --- a/src/frontend/move.cc +++ b/src/frontend/move.cc @@ -559,13 +559,10 @@ leaf * ValidateMove (char *s, char *cleanMove) p = mvstr; do { - if (*s != 'x' && *s != '+' && *s != '=' && !isspace(*s)) + if (*s != 'x' && *s != '+' && *s != '#' && *s != '=' && !isspace(*s)) *p++ = *s; } while (*s++ != '\0' ); - /* Flush castles that check */ - if (mvstr[strlen(mvstr)-1] == '+' || mvstr[strlen(mvstr)-1] == '#' || - mvstr[strlen(mvstr)-1] == '=') mvstr[strlen(mvstr)-1] = '\000'; if (cleanMove) strcpy(cleanMove, mvstr); /* Check for castling */ -- 2.39.5