我编译以下程序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
运行程序时,它不会因运行时边界检查错误而退出。为什么会这样?这是 gfortran 缺少的功能,还是有根本原因为什么这样做是个坏主意?
我知道在某些情况下重新解释具有不同形状的数组可能是有意义的(我猜这在 Fortran 标准中是允许的),例如从 2D 数组到展平的 1D 数组,但在这些情况下元素计数不会改变。重塑为较低的元素数量也可能很好,但绝对不是较大的元素数量,这就是上面发生的情况。
编辑:为了证明程序确实在写入无效的内存地址,我使用电子围栏工具运行它:
$ 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)
同样,在valgrind下运行程序给出:
==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)