【发布时间】:2021-12-15 09:24:55
【问题描述】:
我想调用一个函数,该函数将 Gnu 调试器 (gdb) 中的派生类型作为参数。我最终得到一个段错误。这是一个“最低限度”的工作示例:
module modSimpleClass
type Person
character(len=20) :: Name
contains
procedure PrintName
end type
contains
subroutine PrintName(a)
class(Person) :: a
print *, a%Name
end subroutine
subroutine Print42()
print *, "42"
end subroutine
subroutine PrintNameFromOutside(a)
class(Person) :: a
print *, a%Name
end subroutine
end module
program testgdb
use modSimpleClass
implicit none
type(Person) :: JoeJohnson
JoeJohnson%Name = "Joe Johnson"
call JoeJohnson%PrintName
end program testgdb
我用 gfortran 9.3.0 版 编译它,从 gdb 运行它并在它结束之前停止它。 以下事情有效:
call Print42()
print JoeJohnson%Name
以下事情不起作用:
call JoeJohnson%PrintName()!There is no member named PrintName.
call PrintName(JoeJohnson)!Error then segfault
call PrintNameFromOutside(JoeJohnson)!Error then segfault
错误如下:
正在调试的程序在从 GDB 调用的函数中发出信号。 GDB 保留在接收信号的帧中。 要更改此行为,请使用“set unwindonsignal on”。 评估包含函数的表达式 (modsimpleclass::printname) 将被放弃。 函数执行完毕后,GDB 会静默停止。
如何从gdb正确调用fortran子程序?
感谢您对@Flusslauf 的回复。我将尝试改写您所说的内容:
从gfortran的角度来看,如果我们在模块modsimpleclass中定义了派生类型Person,
- 只有初始化变量的作用域才能看到原始类型。
- 任何作为参数的函数或子程序
该派生类型的对象看到类型
__class_modsimpleclass_Person_t带有属性:-
_data:指向对象的指针。 -
_vptr:指向包含对象信息的指针。
-
因此,一个函数实际上为每个派生类型的对象获取两个指针:一个指向该对象 另一个指向对象的信息。
从 gdb 向函数传递指向对象的指针有效, 但是将对象本身传递给它不起作用。
@Flusslauf 成立
call PrintName( &JoeJohnson )!works because it is equivalent to
call PrintName( a%_data )!this, which works too
call PrintName( a )!this works and it makes sense
call PrintName( a%_data, a%_vptr )!this also works
call PrintName( a%_vptr)!this outputs something strange
call PrintName( *(a%_data) )!causes segfault since equivalent to
call PrintName( JoeJohnson )!Error then segfault
,其中每条指令都在变量的正确范围内执行。
【问题讨论】:
-
这看起来 GDB不支持它,你可以在sourceware.org/bugzilla打开一个错误报告
-
传递对象会使 gdb 将其解释为指针(因为这是这里所期望的),或者我认为是指针对。然后 GDB 尝试取消引用它并落在内存中不应该出现的地方,这会导致 SIGSEGV。
-
一般我认为这个结论是正确的(对于这个版本的gfortran)。传递对象的指针仅有效,因为 _data 是实际传递的 __class_modsimpleclass_Person_t 对象的第一个成员,并且 _vptr(遗憾的是我不知道那是什么)没有被取消引用和使用,我猜。因为从技术上讲,没有人将指向 __class_modsimpleclass_Person_t 的地址交给函数。是否也会使用 _vptr 这个调用应该导致 SIGSEV。
-
@Flusslauf 我将我的编译器版本添加到问题中(gfortran 9.3.0),因为这取决于编译器。我还尝试在函数内部停止并进行不同的调用。他们中的大多数都工作并同意您以前的 cmets。如果你好奇的话,我会在我的问题中添加我尝试过的内容。
标签: segmentation-fault fortran gdb