Debugging 与派生类型相关的Fortran分段错误
我在调试网格生成算法中出现的分段错误时遇到了一些严重的问题。不幸的是,我不能提供一个最低限度的工作示例。我想如果可以的话,我自己解决这个问题已经走了一半。所以基本上我希望有人能就我面临的问题分享一些想法。 来自分段错误的错误消息Debugging 与派生类型相关的Fortran分段错误,debugging,segmentation-fault,fortran,derived-types,Debugging,Segmentation Fault,Fortran,Derived Types,我在调试网格生成算法中出现的分段错误时遇到了一些严重的问题。不幸的是,我不能提供一个最低限度的工作示例。我想如果可以的话,我自己解决这个问题已经走了一半。所以基本上我希望有人能就我面临的问题分享一些想法。 来自分段错误的错误消息 forrtl: severe (174): SIGSEGV, segmentation fault occurred Image PC Routine Line Source
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
gabel_v112 000000000054A346 Unknown Unknown Unknown
gabel_v112 0000000000544C2C Unknown Unknown Unknown
gabel_v112 00000000005093DB Unknown Unknown Unknown
gabel_v112 000000000040103C Unknown Unknown Unknown
gabel_v112 000000000048E3F0 Unknown Unknown Unknown
gabel_v112 0000000000400F17 Unknown Unknown Unknown
通过使用回溯、英特尔调试器和一些老式的写入(,),我认为我能够在以下子例程中缩小分段错误的来源:
SUBROUTINE create_type_12(l)
use types
use parameters
use vars_and_data
implicit none
INTEGER(I4B), INTENT(IN) :: l
INTEGER(I4B) :: b, nl, neighbor, n_11
do b=1, nf(l)
if(levels(l)%blocks(b)%state .EQ. state_interface_undecided) then
n_11 = 0
do nl=1, nlinks
neighbor = levels(l)%blocks(b)%neighbors(nl)
if(neighbor .GT. 0) then
if(levels(l)%blocks(neighbor)%state .EQ. state_fine1) n_11 = n_11 + 1
end if
end do
if(n_11 .GT. 0) levels(l)%blocks(b)%state = state_fine2
end if
end do
END SUBROUTINE create_type_12
更准确地说,这条线
if(levels(l)%blocks(neighbor)%state .EQ. state_fine1) n_11 = n_11 + 1
此子例程操作的数据结构定义如下:
TYPE :: blockinfo
INTEGER(I4B) :: number
INTEGER(I4B) :: state
INTEGER(I4B) :: state_floodfill
INTEGER(I4B) :: state_proximity
INTEGER(I4B), DIMENSION(26) :: neighbors
INTEGER(I4B), DIMENSION(26) :: linktype
INTEGER(I4B) :: parent
INTEGER(I4B), DIMENSION(8) :: children
INTEGER(I4B), DIMENSION(3) :: pos
INTEGER(I4B) :: triangle_amount
INTEGER(I4B) :: triangle_ll
END TYPE blockinfo
TYPE :: block
TYPE(blockinfo), DIMENSION(:), ALLOCATABLE :: blocks
END TYPE block
TYPE(block), DIMENSION(:), ALLOCATABLE :: levels
现在麻烦就从这里开始了。通常,我会使用-check边界进行编译,以确定分段错误的来源。不幸的是-check限制代码正常运行并生成有效的结果数据集。我使用的其他编译器标志是-O3-xSSE4.2-ipo-static-asked buffered_io。Ifort编译器版本为16.0.1和13.1.3。验证了不同机器上的行为
更糟糕的是,如果我更改一些编译标志(例如省略-xSSE4.2),代码运行良好。但是,单独使用-xSSE4.2而不进行任何其他优化,代码也可以正常运行。切换到带有“相似”编译标志的gfortran,代码也可以正常运行
通过进一步调试,我发现当变量b的值为27388461时,就会出现分段错误。但令我惊讶的是,所有级别(l)%blocks(27388461)%neighbor的值都在blocks(这里是102883584)的大小范围内,当然除了负数。所以我不知道是什么导致了分割错误
长话短说,我有三个问题,但欢迎任何其他提示:
使用8字节整数作为“blocktype”派生类型的索引似乎是一种可能的解决方法。但是,为了避免一个出现在几年后的编译器错误,我宁愿考虑切换到一个不同的编译器。如果调试改变了行为,考虑堆栈损坏是一个很好的选择。检查是否使用正确的参数类型和数组大小调用所有子例程和函数。问题可能在崩溃发生的地方以外的其他地方。应该使用-gen接口和-warn接口吗?我已经试过了,但是没有用。这取决于,如果在不同的文件中有对外部过程的调用,它可能不会被检测到。如果你想让我们回答你的问题,你必须准备一个mcve(1)你所有的类型都是动态的——你总是检查分配吗?一切都初始化正确吗?像您报告的编译相关错误可能会暴露这类错误。请记住,错误可能远远看不到其原因。(2) 既然您找到了错误,那么打印所有涉及变量(首先是大小)的所有信息应该会给您带来一些好处(从
nf
开始)。这很严重(174)。。。程序尝试了无效的内存引用--它发生在某个地方。正如Vladimir F所说,仅仅是思考,就需要更多的代码。如果调试改变了行为,那么最好考虑堆栈损坏。检查是否使用正确的参数类型和数组大小调用所有子例程和函数。问题可能在崩溃发生的地方以外的其他地方。应该使用-gen接口和-warn接口吗?我已经试过了,但是没有用。这取决于,如果在不同的文件中有对外部过程的调用,它可能不会被检测到。如果你想让我们回答你的问题,你必须准备一个mcve(1)你所有的类型都是动态的——你总是检查分配吗?一切都初始化正确吗?像您报告的编译相关错误可能会暴露这类错误。请记住,错误可能远远看不到其原因。(2) 既然您找到了错误,那么打印所有涉及变量(首先是大小)的所有信息应该会给您带来一些好处(从nf
开始)。这很严重(174)。。。程序尝试了无效的内存引用--它发生在某个地方。正如Vladimir F所说,为了更好,需要更多的代码。