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

问题描述:

因此,我想帮助我的研究人员调试Fortran程序,为了演示目的,我创建了一个程序故意导致段错误。SEGFAULT以较低的优化级别消失?

这里的源:

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的内部簿记数据并破坏堆。崩溃可能正在等待发生在别的地方,或者可能只是程序的数字结果会有点不对。任何事情都可能发生。