0

I am working on a large Fortran code, where parts are written in FORTRAN77. There is a piece of code, which causes debugger to raise errors like:

Fortran runtime error: 
Index '2' of dimension 1 of array 'trigs' above upper bound of 1

but when compiled without debugging options runs and does not crash the program. Debugging options used:

-g -ggdb -w -fstack-check -fbounds-check\
     -fdec  -fmem-report -fstack-usage

The logic of the problematic piece of code is following: in file variables.cmn I declare

implicit none

integer factors,n
real*8 triggers
parameter (n=32)

common /fft/ factors(19), triggers(6*n)

Variables factors and triggers are initialized in procedure initialize:

include 'variables.cmn'
...
CALL FFTFAX(n,factors,triggers)
...

FFTFAX is declared in another procedure as:

SUBROUTINE FFTFAX(N,IFAX,TRIGS)
implicit real*8(a-h,o-z)
DIMENSION IFAX(13),TRIGS(1)

    CALL FAX (IFAX, N, 3)
    CALL FFTRIG (TRIGS, N, 3)

RETURN
END

and lets look at procedure FFTRIG:

  SUBROUTINE FFTRIG(TRIGS,N,MODE)
  implicit real*8(a-h,o-z)
  DIMENSION TRIGS(1)

        PI=2.0d0*ASIN(1.0d0)
        NN=N/2
        DEL=(PI+PI)/dFLOAT(NN)
        L=NN+NN

        DO 10 I=1,L,2
        ANGLE=0.5*FLOAT(I-1)*DEL
        TRIGS(I)=COS(ANGLE)
        TRIGS(I+1)=SIN(ANGLE)
10 CONTINUE
        DEL=0.5*DEL
        NH=(NN+1)/2
        L=NH+NH
        LA=NN+NN

        DO 20 I=1,L,2
        ANGLE=0.5*FLOAT(I-1)*DEL
        TRIGS(LA+I)=COS(ANGLE)
        TRIGS(LA+I+1)=SIN(ANGLE)
20 CONTINUE

In both FFTFAX and FFTRIG procedures there are different bounds for dimensions of arguments than the actual input array size (for TRIGS it is 1 and 19, respectively). I printed out TRIGS after calling FFTFAX in no-debugger compilation setup:

 trigs:                    1.0000000000000000        0.0000000000000000\
  0.99144486137381038       0.13052619222005157       0.96592582628906831\
  0.25881904510252074       0.92387953251128674       0.38268343236508978\
  ...

My questions are:

  1. Is notation : DIMENSION TRIGS(1) something more than setting bound of an array?
  2. Why is the program even working in no-debugger mode?
  3. Is setting: DIMENSION TRIGS(*) a good fix if I want variable trigs be a result of the procedure?
9
  • Some small remarks: 1) signals indeed array but also its upper limit. 2) no boundary checking performed 3) why not use the real dimension (6*n) Commented May 11, 2018 at 10:46
  • @albert maybe then 4th question is in order: 4) where values in trigs with code run in a normal mode are coming from? Are they some random junk, or there is some connection of with what happens in procedure FFTRIG? @3)Unfortunately I cannot use dimension 6*n becauseFFTFAX is also used for other arguments with different dimension. Commented May 11, 2018 at 10:55
  • I am pretty sure this is a duplicate. But I cannot find any original. Commented May 11, 2018 at 10:59
  • 1
    @VladimirF may be thinking of stackoverflow.com/questions/17891508/… Commented May 11, 2018 at 14:42
  • 1
    @Maria 1) I think it is a very old trick to avoid explicitly specifying the size of a dummy array, and "1" has little meaning (and the upper bound of an actual array argument is usually not 1). 3) Yes, I think setting TRIGS(*) is a good fix (according to your comment above). Commented May 11, 2018 at 20:19

2 Answers 2

1

In f77 statements like the DIMENSION TRIGS(1) or similar or ..(*) with any number, if pertaining an argument of the procedure just tells the compiler the rank of the array, the length in memory must be assigned to the array which is given in the call of the subroutine, normally f77 does not check this! My recommendation either use (*) or better reformat (if necessary) the f77 sources to f90 (the bits shown would compile without change...). and use dimension computed using n in the declaration within the subroutines/procedures. Fortan passes arguments by address (i.e. trigs(i) in the subroutine just will refer on the memory location, which corresponds to the address of trigs(1) + i*size(real*8).

A more consisted way to write the subroutine code could be:

SUBROUTINE FFTRIG(TRIGS,N,MODE)
!   implicit real*8(a-h,o-z)
integer, intent(in) :: n      
real(kind=8)        :: trigs(6*n)
integer             :: mode
!  DIMENSION TRIGS(1)
.....
    PI=2.0d0*ASIN(1.0d0)
.....

or with less ability for the compiler to check

SUBROUTINE FFTRIG(TRIGS,N,MODE)
!   implicit real*8(a-h,o-z)
integer, intent(in) :: n      
real(kind=8)        :: trigs(:)
integer             :: mode
!  DIMENSION TRIGS(1)
.....
    PI=2.0d0*ASIN(1.0d0)
.....
Sign up to request clarification or add additional context in comments.

2 Comments

real(kind=8) is not necessarily the same as real*8 DON'T use it! There are multiple warnings around about this in stackoverflow.
plenty of nits to pick here. dimension trigs(1) is not Fortran 77. It is a violation of standard carried over from a widely used work-around for missing feature in Fortran 66. You have no guarantee what various compilers will do with it when bounds check is turned on. real*8 is a non-standard carry over from IBM proprietary extended f66.
0

To answer your question, I would change TRIGS(1) to TRIGS(*), only to more clearly identify array TRIGS as not having it's dimension provided. TRIGS(1) is a carry over from pre F77 for how to identify this.

Using TRIGS(:) is incorrect, as defining array TRIGS in this way requires any routine calling FFTRIG to have an INTERFACE definition. This change would lead to other errors.

Your question is mixing the debugger's need for the array size vs the syntax excluding the size being provided. To overcome this you could pass the array TRIGS's declared dimension, as an extra declared argument, for the debugger to check. When using "debugger" mode, some compilers do provide hidden properties including the declared size of all arrays.

4 Comments

It does nod need an INTERFACE block, it can also be put into a module, whech can be as simple as a single INCLUDE statement for all subroutines in the file.
The point is that using "CALL FFTRIG (TRIGS, N, 3)" by itself would no longer work, but will lead to a program crash. Using (:) would require a change to all other uses of FFTRIG. It is not a minor correction to a large code.
I don't think so, if you keep N in the argument list. But the explicit interface must be available, that is correct.
What I was attempting to say is that if the only change is "TRIGS(1)" to "TRIGS(:)" in the routine FFTRIG; this can be a risky change to the code. It is not a change that is easy to recognise when checking code (like changing the argument list) but it does require a change to be made to all calls to FFTRIG, throughout the code. Not all compilers will recognise and report this requirement. N is not related to how (:) is implemented.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.