Fortran 95 中的 "Bus Error" 和 "munmap_chunk(): Invalid Pointer"
"Bus Error" and "munmap_chunk(): Invalid Pointer" in Fortran 95
我正在开发一个 python 项目,出于效率原因,该项目通过 f2py 调用 fortran 子例程。
当我执行代码时,它在看似随机(不一致)的点失败并出现分段错误。使用 faulthandler
Python 库,我将搜索范围缩小到 Bus Error
和 munmap_chunk(): Invalid Pointer
错误,尽管错误仍然不一致。
鉴于错误看似随机的性质,我恐怕无法提供 MWE。我的 Fortran 代码是(删节 -- 完整版 here):
module event_rates
contains
subroutine event_rate_f95(events, edges, events_edges, lifetimes, lt_size, NBins)
implicit none
! define input parameters
! define internal variables
dtd = delay_time_distribution(lifetimes, edges, NBins)
print *, "DTD generated"
do i = 1, NBins+1
t1 = events_edges(i-1)
t2 = events_edges(i)
print *, "Ts done"
z1 = estimate_redshift(t1)
z2 = estimate_redshift(t2)
print *, 'computing sfr'
SFR = compute_SFR(z1, z2) / (1E-3) ** 3
print *, "about to enter inner loop"
do j = 0, i-1
! do a computation
enddo
print *, "exited inner loop"
print *, i
enddo
end subroutine
end module event_rates
其中delay_time_distribution, estimate_redshift, compute_SFR
是我之前定义的函数。作为参考,每当我调用它时,NBins
大约是 50。在最近的 3 次执行中,它失败于:
1) i=20
里面 estimate_redshift()
,
2) 在delay_time_distribution()
函数中,
3) 在 Fortran 代码终止并将控制返回给 Python.
之后
从阅读有关这些错误的背景信息来看,这似乎是内存管理问题,因为分段错误正在访问我无法访问的内存,总线错误正在访问不存在的内存,并且 munmap_chunk()
将错误的指针传递给 FREE 指令。但我依靠 Fortran 95 的内置内存管理来为我处理这个问题。在执行代码时监视 htop
显示我的 CPU 使用一个核心峰值,但内存使用保持不变。
我的问题有两个:是什么导致了这些错误,一般如何进一步调试?
调试问题
有一种简单的调试方法:使用调试标志。
您可能知道,如果您使用 gfortran 编译 FORTRAN,则可以将 -fcheck=bounds
传递给 gfortran
命令。同样,您可以将 --opt='-fcheck=bounds'
传递给 f2py3
命令来调试问题。
这个具体问题
我试图访问一个错误的数组。考虑 pastebin 的第 122 行:
bin_low = floor(NBins * (x1 - NBins) / (NBins))
如果x1 = 0
,则bin_low = -NBins
。其中,由于 NBins
(您拥有的箱数)为正,因此变为负。您不能在 FORTRAN 中索引到具有负索引的数组——这是访问无效内存,a.k.a 段错误。
这里的解决办法是约束索引:
bin_low = max(1, floor(NBins * (x1 - NBins) / (NBins)))
这样一来,如果公式为您提供负分格,您将访问第一个分格。 (记住,FORTRAN 是从 1 开始索引的)
我正在开发一个 python 项目,出于效率原因,该项目通过 f2py 调用 fortran 子例程。
当我执行代码时,它在看似随机(不一致)的点失败并出现分段错误。使用 faulthandler
Python 库,我将搜索范围缩小到 Bus Error
和 munmap_chunk(): Invalid Pointer
错误,尽管错误仍然不一致。
鉴于错误看似随机的性质,我恐怕无法提供 MWE。我的 Fortran 代码是(删节 -- 完整版 here):
module event_rates
contains
subroutine event_rate_f95(events, edges, events_edges, lifetimes, lt_size, NBins)
implicit none
! define input parameters
! define internal variables
dtd = delay_time_distribution(lifetimes, edges, NBins)
print *, "DTD generated"
do i = 1, NBins+1
t1 = events_edges(i-1)
t2 = events_edges(i)
print *, "Ts done"
z1 = estimate_redshift(t1)
z2 = estimate_redshift(t2)
print *, 'computing sfr'
SFR = compute_SFR(z1, z2) / (1E-3) ** 3
print *, "about to enter inner loop"
do j = 0, i-1
! do a computation
enddo
print *, "exited inner loop"
print *, i
enddo
end subroutine
end module event_rates
其中delay_time_distribution, estimate_redshift, compute_SFR
是我之前定义的函数。作为参考,每当我调用它时,NBins
大约是 50。在最近的 3 次执行中,它失败于:
1) i=20
里面 estimate_redshift()
,
2) 在delay_time_distribution()
函数中,
3) 在 Fortran 代码终止并将控制返回给 Python.
之后从阅读有关这些错误的背景信息来看,这似乎是内存管理问题,因为分段错误正在访问我无法访问的内存,总线错误正在访问不存在的内存,并且 munmap_chunk()
将错误的指针传递给 FREE 指令。但我依靠 Fortran 95 的内置内存管理来为我处理这个问题。在执行代码时监视 htop
显示我的 CPU 使用一个核心峰值,但内存使用保持不变。
我的问题有两个:是什么导致了这些错误,一般如何进一步调试?
调试问题
有一种简单的调试方法:使用调试标志。
您可能知道,如果您使用 gfortran 编译 FORTRAN,则可以将 -fcheck=bounds
传递给 gfortran
命令。同样,您可以将 --opt='-fcheck=bounds'
传递给 f2py3
命令来调试问题。
这个具体问题
我试图访问一个错误的数组。考虑 pastebin 的第 122 行:
bin_low = floor(NBins * (x1 - NBins) / (NBins))
如果x1 = 0
,则bin_low = -NBins
。其中,由于 NBins
(您拥有的箱数)为正,因此变为负。您不能在 FORTRAN 中索引到具有负索引的数组——这是访问无效内存,a.k.a 段错误。
这里的解决办法是约束索引:
bin_low = max(1, floor(NBins * (x1 - NBins) / (NBins)))
这样一来,如果公式为您提供负分格,您将访问第一个分格。 (记住,FORTRAN 是从 1 开始索引的)