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