SEGFAULT以较低的优化级别消失?

时间:2017-08-10 05:28:54

标签: fortran gfortran

所以,我想帮助我的研究人员调试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不会。{/ p>

我非常关注这一点。毕竟,如果在启用调试符号的情况下编译错误,我该如何正确调试?

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

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

1 个答案:

答案 0 :(得分:3)

段错误是undefined behaviour。该程序不符合Fortran标准,因此您不能指望任何特定结果。它可以做任何事情。你不能指出发生了一个段错误,对它没有发生时就不那么深切了。

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

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

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