Silverfrost Forums

Welcome to our forums

Using /checkmate does not help catch ASSIGNed GOTO bug

9 Jan 2022 1:19 #28649

The Assigned GOTO feature was deleted in Fortran 95, but FTN95 still supports that Fortran feature, and there are occasional old Fortran codes that we encounter in which it was used.

The Assigned GOTO is governed by some peculiar rules (see 7.1.1.3 of the Fortran 66 standard, https://wg5-fortran.org/ARCHIVE/Fortran66.pdf ). A variable of type integer may be assigned a statement number (including a Format statement number). That integer variable may no longer be used in contexts where an integer arithmetical value is expected. However, assigning a new integer value to it restores the status of the variable to that of a normal integer variable, and the variable may no longer be used in Assigned GOTO statements until it is set equal to a new statement number with an ASSIGN statement.

The following short code encapsulates a situation where FTN95 used with /CHECK or /CHECKMATE does not help to catch the bug.

      program wicked
      implicit none
      integer pqr
      data pqr/789/
!
   10 print *,'pqr = ',pqr
      if(pqr .gt. 10)then  ! invalid comparison when PQR is a stmt.no.
         assign 10 to pqr  ! now the integer value of PQR is undefined
         goto pqr
      else
         pqr = 1           ! now the stmt.no. value of PQR is undefined
      endif
      print *,pqr
      end 

The resulting EXE, when run, loops until it is terminated with a ^C.

Using a single name (PQR) for an integer variable and a statement label was surely an invitation for trouble, and having the compiler issue a suitable warning would help in detecting and fixing bugs of this type -- such as:

  PQR - both a numeric value and label assigned to this variable. 
10 Jan 2022 7:45 #28650

mecej4

Thank you for the feedback. I have logged this for investigation.

13 Jan 2022 5:07 #28659

The following extended code demonstrates that ASSIGN allocates a memory address using FTN95 /32, pqr_10 = 4198492, pqr = 789 then 4198492

FTN95 /64 updates pqr with a value = 5614, associated with assign 10 to pqr. Not sure what 5612 is ? pqr_10 = 5614, pqr = 789 then 5614 looks like 'integer pqr' and 'assign pqr' are the same variable.

Using gFortran (x64) in PLATO, the value of PQR does not appear to change, which could imply that 'integer pqr' and 'assign pqr' might be different, although pqr_10 does have a value ? pqr_10 = 11, pqr = 789 and are unchanged for print, *

My recollection of use with other F77 compilers, you can't use 'goto pqr' until 'assign xx to pqr' has been performed. I am sure there would have been variability with this.

      program wicked
      implicit none
      integer pqr, pqr_orig, pqr_10, pqr_1, num
      data pqr, pqr_10 /789, 11 /
!
!z      assign 798 to pqr
      pqr_orig = pqr
      assign 10 to pqr_10
!z      assign 1 to pqr_1
      num = 0
!
   10 print *,'pqr = ',pqr, pqr_orig, pqr_10, num
      num = num+1
      if (pqr .gt. 10)then  ! invalid comparison when PQR is a stmt.no.
         assign 10 to pqr  ! now the integer value of PQR is undefined
         if ( num < 11 ) goto pqr
      else
         pqr = 1           ! now the stmt.no. value of PQR is undefined
      endif
  789 print *,pqr
      end
13 Jan 2022 4:37 #28662

My recollection of use with other F77 compilers, you can't use 'goto pqr' until 'assign xx to pqr' has been performed.

Agree. Similarly, one can't use 'pqr = pqr+1', etc., when pqr is holding a statement label.

The code that I posted is in error. The problem is that the compiler seems unable to catch and flag the error.

As you surmised, the memory location assigned to PQR contains the address of a label, or an integer value. Here are pieces of the 32-bit assembly code.

   0006      10 print *,'pqr = ',pqr                                                             AT 20
      00000020(16/3/9)        Label     __L10
...
   0008            assign 10 to pqr  ! now the integer value of PQR is undefined                 AT 8c
      0000008c(46/5/34)          lea       eax,address of __L10
      00000092(47/5/34)          mov       PQR,eax
   0009            goto pqr                                                                      AT 98
      00000098(48/5/38)          jmp       *PQR

There appears to be no record kept as to whether the current value is an address or an integer.

The 64 bit version does things a bit differently. Instead of storing the address, which is 8 bytes long and too big to store in the 4 byte integer PQR, it subtracts the RBP register from the address, obtaining a 4 byte offset, which it stores in PQR. When the corresponding assigned GOTO is executed, it fetches the value from PQR, adds back RBP, and jumps to the resulting 8 byte address.

8 Feb 2022 3:46 #28762

mecej4

This issue turns out to be rather tricky. I can make the sample program fault at the assignment 'pqr = 1' but to get it to fault for the other invalid usage would be non-trivial.

However, this simple change causes our test suite to fail for 4 programs. Two are programming errors that are easily corrected but in the other two the variable is used consistently in different localities (in one part of the program the variable is used as a simple integer whilst in another independent part it is used as a label).

So there is a risk of breaking working legacy code. We can't make use of /ISO because ASSIGN is deleted and fails anyway.

8 Feb 2022 7:09 #28763

Paul, we can live with being unable to catch ASSIGN related errors at run time, since it is a deleted feature of the language.

I looked at the cross-reference list generated for this program with /xref, hoping to see signs of the dual role played by the variable PQR, but that listing does not reveal that PQR has any relation to statement labels.

8 Feb 2022 7:15 #28764

On further reflection I can provide a warning not an error then the user can upgrade it to an error if preferred.

Please login to reply.