2

I compile the following program with gfortran -g -fcheck=all -Wall bug.F90:

program main
    implicit none

    real, dimension(:), allocatable :: arr

    allocate (arr(5))
    ! should fail, but happily writes out of bounds
    call foo(arr)

contains

subroutine foo(arr)
    real, dimension(10), intent(inout) :: arr

    arr(10) = 42
end subroutine

end program

When running the program, it doesn't exit with a runtime bounds check error. Why is that the case? Is this a missing feature of gfortran or is there a fundamental reason why doing this would be a bad idea?

I understand that there are situations where reinterpreting an array with a different shape may make sense (and I guess this is allowed in the Fortran standard), for example to go from a 2D array to a flattened 1D array, but in those cases the element count wouldn't change. Reshaping to a lower element count may be fine as well, but definitely not a larger element count, which is what is happening above.

EDIT: To demonstrate that the program is indeed writing to invalid memory addresses I ran it using the electric fence tool:

$ LD_PRELOAD=libefence.so.0.0 ./a.out

  Electric Fence 2.2 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
#0  0x7f1f6e42b2da in ???
#1  0x7f1f6e42a503 in ???
#2  0x7f1f6e04ef1f in ???
#3  0x7f1f6ee00885 in foo
        at bug.F90:16
#4  0x7f1f6ee0099d in MAIN__
        at bug.F90:8
#5  0x7f1f6ee009df in main
        at bug.F90:8
Segmentation fault (core dumped)

Similarly, running the program under valgrind gives:

==1162== Invalid write of size 4
==1162==    at 0x108885: foo.3498 (bug.F90:16)
==1162==    by 0x10899D: MAIN__ (bug.F90:8)
==1162==    by 0x1089DF: main (bug.F90:8)
==1162==  Address 0x5e05ae4 is 16 bytes after a block of size 20 alloc'd
==1162==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1162==    by 0x108930: MAIN__ (bug.F90:6)
==1162==    by 0x1089DF: main (bug.F90:8)
letmaik
  • 3,348
  • 1
  • 36
  • 43
  • I'm not sure that it does write out of bounds. `foo` requires a 10-long array, but you only supply a 5-length one. My suspicion, though I might be wrong, is that the binary creates a new 10-long array, copies the first 5 values from `arr` into it, then runs the subroutine. When it's finished, it copies the first 5 elements back to the main program's `arr` array. But since the subroutine's `arr` has length 10, writing to the 10s element is not a bound violation. – chw21 Nov 06 '18 at 00:03
  • In fact, I tried it out. If you replace the `dimension(10)` in the subroutine's declaration section with `dimension(:)` then you get the bounds violation, because it then gets the size of `arr` from the argument itself. – chw21 Nov 06 '18 at 00:06
  • Writing `shape(arr)` in the main program and in the subroutine go in that direction: locally, the array has size 10. ifort 18.0.1 (linux x86_64) happily produces the same output. – Pierre de Buyl Nov 06 '18 at 08:10
  • See my edit, there is no copying going on, invalid memory is definitely accessed/written. – letmaik Nov 06 '18 at 09:33
  • 3
    The code is wrong there is no doubt about that. This isn't a bounds violation in the access `arr(10)` but is a failure in the argument association. I'm not aware of a gfortran option for this (otherwise I'd post an answer), but other compilers certainly do offer such run-time checks, – francescalus Nov 06 '18 at 09:36
  • @letmaik, as the source code to gfortran is available for inspection, I suspect the gfortran developers would accept a patch to the compiler to address the issue. – evets Nov 06 '18 at 15:40
  • I found https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82243 which seems to be the same issue. – letmaik Nov 10 '18 at 15:18

0 Answers0