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


Reply via email to