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?
Maria
  • 84
  • 4
  • 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) – albert May 11 '18 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 because`FFTFAX` is also used for other arguments with different dimension. – Maria May 11 '18 at 10:55
  • I am pretty sure this is a duplicate. But I cannot find any original. – Vladimir F Героям слава May 11 '18 at 10:59
  • 3) But n is an argument of the function so should be OK? 4) in non-debug mode you are "lucky" the address of the array is given and as no boundaries are checked it just writes it in this case on the right place. @VladimirF I' also pretty sure it is a duplicate, but didn't look for it. – albert May 11 '18 at 11:10
  • And BTW, Maria, please use tag [tag:fortan] for all Fortran questions. This is one of the reasons only 9 people have seen you question so far. Tags are **extremely important** and very few people follow the [tag:fortan77] or the [tag:gfortan] tag. – Vladimir F Героям слава May 11 '18 at 11:59
  • 1
    @VladimirF may be thinking of https://stackoverflow.com/questions/17891508/how-can-a-scalar-be-passed-to-a-vector-1d-array-to-a-fortran-subroutine – High Performance Mark May 11 '18 at 14:42
  • @HighPerformanceMark articles mentioned there are really useful, but in this case it is the other way round - we call procedure with full array `TRIGS` and reduce it inside to the first element, then loop over the whole array. – Maria May 11 '18 at 17:03
  • 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). – roygvib May 11 '18 at 20:19
  • `TRIGS(*)` produces wrong output. I will try to go with `intent(in)` and `intent(out)` statements combined with explicit dimension size – Maria May 12 '18 at 10:38

2 Answers2

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)
.....
Michael
  • 42
  • 3
  • 3
    real(kind=8) is not necessarily the same as real*8 DON'T use it! There are multiple warnings around about this in stackoverflow. – albert May 11 '18 at 18:25
  • 2
    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. – tim18 May 12 '18 at 12:12
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.

johncampbell
  • 203
  • 2
  • 6
  • 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. – Vladimir F Героям слава Jun 04 '18 at 05:26
  • 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. – johncampbell Jun 04 '18 at 13:49
  • I don't think so, if you keep N in the argument list. But the explicit interface must be available, that is correct. – Vladimir F Героям слава Jun 04 '18 at 13:56
  • 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. – johncampbell Jun 05 '18 at 00:47