ker2x
ker2x

Reputation: 450

Problem with Fortran substring comparison of different length

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

Answers (1)

IanH
IanH

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

Related Questions