Unexpected allocatable behaviour

I’m trying to better understand allocatable, something that I don’t fully understand and feel like could introduce a ton of hard-to-find errors is that I can access any index even if I haven’t allocated the array up to that dimension. A simple example would be this:

program main
    implicit none
    real, allocatable :: x(:, :)
    integer :: i

    allocate(x(2, 2))

    x(1, :) = [1, 2]
    x(2, :) = [3, 5]

    do i=1, 10
        print *, x(i, :)
    end do

end program main

which outputs:

  1.00000000       2.00000000
   3.00000000       5.00000000
   0.00000000       0.00000000
   2.00000000       1.68919523E-40
   5.00000000       0.00000000
   0.00000000       0.00000000
   1.68919523E-40   0.00000000
   0.00000000       0.00000000
   0.00000000       0.00000000
   0.00000000       0.00000000

I would expect an error after i=3 but that’s not the case. Is there any way to avoid this behavior?

1 Like

Hi! yes, there is the “-check bounds” (ifort) flag that can help you out! this might take a bit of performance out of your execution but the code will indeed be much more reliable

Without the flag:
image

For gfortran check this thread: fortran - gfortran -fbounds-check doesn't always work? - Stack Overflow

Fortran does not have any automatic bounds check. And it has nothing to do with allocatables. You will get similar results with a “static” array.

@fedebenelli ,

Your concerns are legit, 'most everyone can empathize with you and relate to your needs.

Under the circumstances, you may want to consider the following:

  1. see if it is viable for you to use more than Fortran compiler to test your code and luckily in this respect, you have the advantage of tapping into gfortran, Intel Fortran, LFortran, etc.
  2. view the compiler as two different ones, a debugging compiler and an optimizing one. Use the former during your development and the latter to achieve peak performance. Then with the debugging compiler (e.g., with -g compiler option), look into the available options such as with Intel Fortran’s -check:bounds, -check:pointer, etc. to test drive your code. Other compilers may offer similar or other options, check their documentation.
  3. Also, see if defensive programming is possible for you. Fortran language offers some “tools” for the same. For example, with the code in the original post, you can do
   real, allocatable :: x(:, :)
   integer :: i

   allocate(x(2, 2))

   x(1, :) = [1, 2]
   x(2, :) = [3, 5]

   if ( allocated(x) ) then 
      do i = lbound(x,dim=1), ubound(x,dim=1)
        print *, x(i, :)
      end do
   end if

end

which will output:

C:\temp>gfortran -ffree-form p.f -o p.exe

C:\temp>p.exe
   1.00000000       2.00000000
   3.00000000       5.00000000

Best,

Runtime checks like bound-checking can be computationaly expensive, and Fortran is traditionnally targeting high performance computing. That’s why the standard doesn’t require the compilers to perform runtime checks, and that’s why the compilers do not apply them by default.

A good point is that Fortran arrays begin at 1 by default, so bound errors are less frequent than in C… :grinning:

Hi @fedebenelli,

Your “which outputs:” shows output that is different from @hkvzjal’s expected output, without any “check bounds” , as for i=3 you are reporting 0 0. This is surprising.
Can you report the compiler, OS and compile options you used ?

I am not sure if @FortranFan 's approach helps, as to me, the allocate(x(2,2)) is fairly clear. I can’t see any justification for suggesting the x(2,2) allocated status has changed.

As for using i > 2, although it is out of bounds, the memory referencing should not produce the unusual results you are reporting.
I would expect x(3,1) would be the equivalent to array address x(1,2), as based on your code example, there is no reason to suggest the array is not using contiguous memory.