Reputation: 450
I am reading stdin in a loop and do some comparaison with a bunch of "if" to decide what to do according to the input.
Here is a shortened snippet of the code :
CHARACTER (len= :), allocatable :: input
CHARACTER (len=4096) :: inbuffer ! frustrating but... well, fortran :3
DO
! get input
READ(*, '(a)') inbuffer ! because apparently you can't have allocation on read so you can't just read "input". meh.
input = TRIM(inbuffer)
CALL debug_log(input)
IF(input .EQ. 'uci') THEN
CALL debug_log(" printing uci info")
!isready
ELSE IF(input .EQ. 'isready') THEN
CALL debug_log(" isready -> readyok")
WRITE(*, '(a)') "readyok"
!ucinewgame
ELSE IF(input .EQ. 'ucinewgame') THEN
CALL debug_log("not implemented : reset board and start a new game")
!position
ELSE IF(input(1:8) .EQ. 'position') THEN
CALL debug_log("not implemented : set position")
!quit -> exit main loop
ELSE IF(input .EQ. 'quit') THEN
CALL debug_log(" quit command issued, exiting main loop")
EXIT
!non uci command
!nothing yet
!unknown command
ELSE
CALL debug_log(" ignoring invalid command")
END IF
end do
The input will expect command like "position 123 23415 etc..."
If I type "posi" it's say it's an invalid command as expected.
If I type "position" it say it's not implemented as expected too.
However:
My guess is that it read 8 character even if the input is only 4 and since the previous command was "position" it make posi + tion = position
Here is some log to demonstrate:
** opening debug file : 20181111 / 223418.127
223418.127 : Initializing Fortiche engine
223418.129 : Entering main loop
223420.859 : posi
223420.859 : ignoring invalid command
223426.467 : xxxxtion
223426.467 : ignoring invalid command
223430.498 : posi
223430.498 : not implemented : set position
223437.323 : xxxxxxxxx
223437.323 : ignoring invalid command
223439.418 : posi
223439.418 : ignoring invalid command
223443.979 : position
223443.979 : not implemented : set position
223447.122 : quit
223447.122 : quit command issued, exiting main loop
223447.122 : closing, bye
xxxxtion + posi = position
Which is clearly wrong but I can understand how it ended up like this.
Should I use something other than .EQ.? When I print the input it clearly doesn't print the input + whatever garbage was left behind in memory. But it's doing it when comparing string of possibly different length.
What can I do to solve this problem?
I'm not even started with the hardcore parsing and I already have a problem.
I'm using GNU Fortran on Windows.
Yes, it's UCI stuff as Universal Chess Interface.
EDIT : Full source code : https://github.com/ker2x/fortiche (comment the dirty hack at line 107 & 108 to reproduce the problem)
Upvotes: 2
Views: 927
Reputation: 21451
Substring references need to have starting and ending positions that are within the limits of the string.
You don't defend against a string that has a length less than eight prior to the substring reference input(1:8) .eq. 'position'
.
With input shorter than eight characters, your program is non-conforming, anything can then happen, where anything very reasonably includes the behaviour you see.
Runtime debugging options may help to catch this programming error, depending on the capabilities of your compiler.
Upvotes: 6