f2py 回调中的段错误
segfault on f2py callback
我正在研究分形生成器代码。主要代码用 python 编写,迭代部分用 fortran 编写。我使用 f2py 将两个代码粘合在一起。
这是我使用的 fortran 函数:
function iterate(z0, func, zmax, niter) result(n)
implicit none
complex(kind=8), intent(in) :: z0
real(kind=8), intent(in) :: zmax
integer, intent(in) :: niter
external func
complex(kind=8) :: func
integer :: n
complex(kind=8) :: z
n = 0
z = z0
do while ((n < niter) .and. (abs(z) < zmax))
z = func(z)
n = n + 1
end do
end function iterate
这是生成的包装器代码的文档字符串:
n = iterate(z0,func,zmax,niter,[func_extra_args])
Wrapper for ``iterate``.
Parameters
----------
z0 : input complex
func : call-back function
zmax : input float
niter : input int
Other Parameters
----------------
func_extra_args : input tuple, optional
Default: ()
Returns
-------
n : int
Notes
-----
Call-back functions::
def func(z): return z
Required arguments:
z : input complex
Return objects:
z : complex
我在尝试时遇到 Segmentation fault
错误
将 iterate
与任何 python 回调函数一起使用。
这是我得到的示例结果:
>>> from foo import iterate
>>> iterate(1.0j, lambda x: 4.0 + x**2, 4.0, 256)
Segmentation fault
我已经查看了所有关于 f2py 回调的可用文档,但是
还没有找到解决这个问题的方法。任何帮助将不胜感激。
更新
这是来自 gdb 的回溯:
Program received signal SIGSEGV, Segmentation fault.
cb_func_in_iterate2__user__routines (return_value=0x7fffffffdbc0, z_cb_capi=0x3ff0000000000000)
at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c:470
470 /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c: No such file or directory.
(gdb) backtrace
#0 cb_func_in_iterate2__user__routines (return_value=0x7fffffffdbc0, z_cb_capi=0x3ff0000000000000)
at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c:470
#1 0x00007ffff6b6482b in iterate2 (z0=(1,1), func=func@entry=0x7ffff6b60c20 <cb_func_in_iterate2__user__routines>, zmax=4, niter=256)
at julia.f90:38
#2 0x00007ffff6b64897 in f2pywrapiterate2 (iterate2f2pywrap=0, z0=(1,1), func=func@entry=0x7ffff6b60c20 <cb_func_in_iterate2__user__routines>,
zmax=4, niter=256) at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/julia-f2pywrappers.f:25
#3 0x00007ffff6b61f5e in f2py_rout_julia_iterate2 (capi_self=<optimized out>, capi_args=<optimized out>, capi_keywds=<optimized out>,
f2py_func=0x7ffff6b64880 <f2pywrapiterate2>) at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c:811
#4 0x00000000004caaa1 in PyEval_EvalFrameEx ()
#5 0x00000000004c87a1 in PyEval_EvalCodeEx ()
#6 0x00000000005030ef in ?? ()
#7 0x00000000004f8c72 in PyRun_FileExFlags ()
#8 0x00000000004f7d77 in PyRun_SimpleFileExFlags ()
#9 0x00000000004982f2 in Py_Main ()
#10 0x00007ffff6f12b45 in __libc_start_main (main=0x497d80 <main>, argc=2, argv=0x7fffffffe2a8, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffe298) at libc-start.c:287
#11 0x0000000000497ca0 in _start ()
我有一个解决方法,但恐怕不是一个完整的修复方法。关键点似乎是当 func
是一个函数时,f2py
会生成一些看起来很奇怪,而且可能只是不正确的 c 代码。将 func
更改为子例程似乎可以正常工作。
要使您的代码正常工作,请更改以下内容:
external func
complex(kind=8) :: func
...
do while ((n < niter) .and. (abs(z) < zmax))
z = func(z)
...
至
interface foo
subroutine func(f, z)
complex(kind=8), intent(out) :: f
complex(kind=8), intent(in) :: z
end subroutine func
end interface foo
...
do while ((n < niter) .and. (abs(z) < zmax))
call func(z, z)
...
这对我来说很好用,并且给出了正确的答案。如果你对此感到满意,你可以停止阅读。以下是我如何解决它的方法。
至于为什么会这样,需要运行f2py
点赞
f2py -m modname -h iterate.pyf iterate.f90
f2py -c --debug --build-dir build iterate.pyf iterate.f90
然后我们可以使用gdb python
调试代码,然后
run -c "import iterate; iterate.iterate(1.0j, lambda x: 4.0 + x*x, 4.0, 256)"
(虽然从它的声音来看,你可能已经了解了这么多)。这样做,我们发现它在 build/src.linux-x86_64.3.4/iteratemodule.c
中的以下行出现段错误(您的目录可能不同):
complex_double z=(*z_cb_capi);
z_cb_capi
是 0x0
,因此出现段错误。这出现在 Fortran 代码中调用 func
时实际调用的 Cython 辅助函数中。函数声明就出现在上面一行之前,在 func
是函数而不是子例程的版本中,它看起来像下面的乱七八糟的东西:
static
#ifdef F2PY_CB_RETURNCOMPLEX
complex_double
#else
void
#endif
cb_func_in_iterate__user__routines (
#ifndef F2PY_CB_RETURNCOMPLEX
complex_double *return_value
#endif
#ifndef F2PY_CB_RETURNCOMPLEX
,
#endif
complex_double *z_cb_capi) {
本质上是以下之一:
static void cb_func_in_iterate__user__routines (complex_double *return_value, complex_double *z_cb_capi)
static complex_double cb_func_in_iterate__user__routines (complex_double *z_cb_capi)
取决于是否定义了F2PY_CB_RETURNCOMPLEX
。 F2PY_CB_RETURNCOMPLEX
似乎从未被定义,因为 gdb 报告该函数具有第一个定义,但它被调用时就好像它是第二个定义一样。您可以看到这一点,因为 return_value
在 Fortran 代码中设置为 z
的地址,并且没有任何 (NULL
) 传递给 z_cb_capi
.
因此,这最终引导我们采用第二种方法来解决此问题:将 -DF2PY_CB_RETURNCOMPLEX
传递给 f2py
:
f2py -c -DF2PY_CB_RETURNCOMPLEX --debug --build-dir build iterate.pyf iterate.f90
然后以第二种形式编译 cb_func_in_iterate__user__routines
,这意味着它确实被正确调用。
现在,我认为您不必这样做,所以我怀疑这是 f2py
中的错误。
我正在研究分形生成器代码。主要代码用 python 编写,迭代部分用 fortran 编写。我使用 f2py 将两个代码粘合在一起。 这是我使用的 fortran 函数:
function iterate(z0, func, zmax, niter) result(n)
implicit none
complex(kind=8), intent(in) :: z0
real(kind=8), intent(in) :: zmax
integer, intent(in) :: niter
external func
complex(kind=8) :: func
integer :: n
complex(kind=8) :: z
n = 0
z = z0
do while ((n < niter) .and. (abs(z) < zmax))
z = func(z)
n = n + 1
end do
end function iterate
这是生成的包装器代码的文档字符串:
n = iterate(z0,func,zmax,niter,[func_extra_args])
Wrapper for ``iterate``.
Parameters
----------
z0 : input complex
func : call-back function
zmax : input float
niter : input int
Other Parameters
----------------
func_extra_args : input tuple, optional
Default: ()
Returns
-------
n : int
Notes
-----
Call-back functions::
def func(z): return z
Required arguments:
z : input complex
Return objects:
z : complex
我在尝试时遇到 Segmentation fault
错误
将 iterate
与任何 python 回调函数一起使用。
这是我得到的示例结果:
>>> from foo import iterate
>>> iterate(1.0j, lambda x: 4.0 + x**2, 4.0, 256)
Segmentation fault
我已经查看了所有关于 f2py 回调的可用文档,但是 还没有找到解决这个问题的方法。任何帮助将不胜感激。
更新
这是来自 gdb 的回溯:
Program received signal SIGSEGV, Segmentation fault.
cb_func_in_iterate2__user__routines (return_value=0x7fffffffdbc0, z_cb_capi=0x3ff0000000000000)
at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c:470
470 /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c: No such file or directory.
(gdb) backtrace
#0 cb_func_in_iterate2__user__routines (return_value=0x7fffffffdbc0, z_cb_capi=0x3ff0000000000000)
at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c:470
#1 0x00007ffff6b6482b in iterate2 (z0=(1,1), func=func@entry=0x7ffff6b60c20 <cb_func_in_iterate2__user__routines>, zmax=4, niter=256)
at julia.f90:38
#2 0x00007ffff6b64897 in f2pywrapiterate2 (iterate2f2pywrap=0, z0=(1,1), func=func@entry=0x7ffff6b60c20 <cb_func_in_iterate2__user__routines>,
zmax=4, niter=256) at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/julia-f2pywrappers.f:25
#3 0x00007ffff6b61f5e in f2py_rout_julia_iterate2 (capi_self=<optimized out>, capi_args=<optimized out>, capi_keywds=<optimized out>,
f2py_func=0x7ffff6b64880 <f2pywrapiterate2>) at /tmp/tmpT8xG1q/src.linux-x86_64-2.7/juliamodule.c:811
#4 0x00000000004caaa1 in PyEval_EvalFrameEx ()
#5 0x00000000004c87a1 in PyEval_EvalCodeEx ()
#6 0x00000000005030ef in ?? ()
#7 0x00000000004f8c72 in PyRun_FileExFlags ()
#8 0x00000000004f7d77 in PyRun_SimpleFileExFlags ()
#9 0x00000000004982f2 in Py_Main ()
#10 0x00007ffff6f12b45 in __libc_start_main (main=0x497d80 <main>, argc=2, argv=0x7fffffffe2a8, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffe298) at libc-start.c:287
#11 0x0000000000497ca0 in _start ()
我有一个解决方法,但恐怕不是一个完整的修复方法。关键点似乎是当 func
是一个函数时,f2py
会生成一些看起来很奇怪,而且可能只是不正确的 c 代码。将 func
更改为子例程似乎可以正常工作。
要使您的代码正常工作,请更改以下内容:
external func
complex(kind=8) :: func
...
do while ((n < niter) .and. (abs(z) < zmax))
z = func(z)
...
至
interface foo
subroutine func(f, z)
complex(kind=8), intent(out) :: f
complex(kind=8), intent(in) :: z
end subroutine func
end interface foo
...
do while ((n < niter) .and. (abs(z) < zmax))
call func(z, z)
...
这对我来说很好用,并且给出了正确的答案。如果你对此感到满意,你可以停止阅读。以下是我如何解决它的方法。
至于为什么会这样,需要运行f2py
点赞
f2py -m modname -h iterate.pyf iterate.f90
f2py -c --debug --build-dir build iterate.pyf iterate.f90
然后我们可以使用gdb python
调试代码,然后
run -c "import iterate; iterate.iterate(1.0j, lambda x: 4.0 + x*x, 4.0, 256)"
(虽然从它的声音来看,你可能已经了解了这么多)。这样做,我们发现它在 build/src.linux-x86_64.3.4/iteratemodule.c
中的以下行出现段错误(您的目录可能不同):
complex_double z=(*z_cb_capi);
z_cb_capi
是 0x0
,因此出现段错误。这出现在 Fortran 代码中调用 func
时实际调用的 Cython 辅助函数中。函数声明就出现在上面一行之前,在 func
是函数而不是子例程的版本中,它看起来像下面的乱七八糟的东西:
static
#ifdef F2PY_CB_RETURNCOMPLEX
complex_double
#else
void
#endif
cb_func_in_iterate__user__routines (
#ifndef F2PY_CB_RETURNCOMPLEX
complex_double *return_value
#endif
#ifndef F2PY_CB_RETURNCOMPLEX
,
#endif
complex_double *z_cb_capi) {
本质上是以下之一:
static void cb_func_in_iterate__user__routines (complex_double *return_value, complex_double *z_cb_capi)
static complex_double cb_func_in_iterate__user__routines (complex_double *z_cb_capi)
取决于是否定义了F2PY_CB_RETURNCOMPLEX
。 F2PY_CB_RETURNCOMPLEX
似乎从未被定义,因为 gdb 报告该函数具有第一个定义,但它被调用时就好像它是第二个定义一样。您可以看到这一点,因为 return_value
在 Fortran 代码中设置为 z
的地址,并且没有任何 (NULL
) 传递给 z_cb_capi
.
因此,这最终引导我们采用第二种方法来解决此问题:将 -DF2PY_CB_RETURNCOMPLEX
传递给 f2py
:
f2py -c -DF2PY_CB_RETURNCOMPLEX --debug --build-dir build iterate.pyf iterate.f90
然后以第二种形式编译 cb_func_in_iterate__user__routines
,这意味着它确实被正确调用。
现在,我认为您不必这样做,所以我怀疑这是 f2py
中的错误。