SEGFAULT 随着优化级别的降低而消失?

SEGFAULT disappears with lower optimisation level?

所以,我想帮助我的研究人员调试 Fortran 程序,出于演示目的,我创建了一个 故意 导致段错误的程序。

来源如下:

program segfault

  implicit none
  integer :: n(10), i
  integer :: ios, u

  open(newunit=u, file='data.txt', status='old', action='read', iostat=ios)
  if (ios /= 0) STOP "error opening file"
  i = 0
  do
    i = i + 1
    read(u, *, iostat=ios) n(i)
    if (ios /= 0) exit
  end do
  close(u)

  print*, sum(n)

end program segfault

data.txt 文件包含 100 个随机数:

for i in {1..100}; do 
    echo $RANDOM >> data.txt; 
done

当我用

编译这个程序时
gfortran -O3 -o segfault.exe segfault.f90

生成的可执行文件尽职尽责地崩溃了。但是当我启用调试编译时:

gfortran -O0 -g -o segfault.exe segfault.f90

然后它只读入前 10 个值,并打印它们的总和。对于它的价值,-O2 会导致所需的段错误,-O1 不会。

我深感忧虑。毕竟,如果在启用调试符号的情况下编译时错误消失了,我该如何正确调试?

有人可以解释这种行为吗?

我正在使用GNU Fortran (MacPorts gcc5 5.3.0_1) 5.3.0

段错误是 undefined behaviour。该程序不符合 Fortran 标准,因此您不能期待任何特定的结果。它可以做任何事情。你不能指望段错误会发生,当它没有发生时,你越不担心。

编译器检查 (fcheck=) 和清理 (-fsanitize=) 可用是有原因的。等待段错误不能保证有效。不在 Fortran 中,不在 C 中,不在任何类似的语言中。

不合格程序的结果可能取决于许多因素,例如变量在内存或寄存器中的位置。内存中变量的对齐,堆栈帧的位置......你根本无法计算任何东西。这些细节显然取决于优化级别。

如果程序越界访问数组,但内存中的地址恰好是属于进程的内存的一部分,则可能不会发生段错误。它只是内存中的一些字节,允许进程读取或写入(或两者)。您可能正在覆盖其他一些变量,您可能正在从一些旧的堆栈框架中读取一些垃圾,您可能正在覆盖 malloc 的内部簿记数据并破坏堆。崩溃可能在其他地方等待发生,或者可能只是程序的数字结果会有点错误。什么事都有可能发生。