简体   繁体   English

在f2py回调上出现segfault

[英]segfault on f2py callback

I am working on fractal generator code. 我正在研究分形生成器代码。 The main code is written in python and iterations part is written in fortran. 主要代码用python编写,迭代部分用fortran编写。 I use f2py to glue the two codes together. 我使用f2py将两个代码粘合在一起。 Here is the fortran function I use: 这是我使用的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 

Here is the docstring for the generated wrapper code: 这是生成的包装器代码的文档字符串:

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

I am getting Segmentation fault error when trying to use iterate with any python callback function. 尝试与任何python回调函数一起使用iterate时,出现Segmentation fault错误。 Here is a sample result that I get: 这是我得到的示例结果:

>>> from foo import iterate
>>> iterate(1.0j, lambda x: 4.0 + x**2,  4.0, 256)
Segmentation fault

I have looked through all available documentation on callbacks in f2py but haven't found any solution to this problem. 我浏览了f2py中有关回调的所有可用文档,但没有找到解决此问题的任何方法。 Any help would be appreciated. 任何帮助,将不胜感激。

UPDATE 更新

Here is a backtrace from gdb: 这是来自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 ()

I've got a workaround, but not a complete fix, I'm afraid. 恐怕我有解决方法,但没有完整的解决方法。 The key point seems to be that f2py generates some strange looking, and possibly just incorrect, c code when func is a function. 关键点似乎是,当func是函数时, f2py生成一些奇怪的外观,甚至可能是错误的c代码。 Changing func to be a subroutine seems to make it work. func更改为子例程似乎可以使其起作用。

To make your code work, change the following: 要使代码正常工作,请更改以下内容:

external func
complex(kind=8) :: func

...

do while ((n < niter) .and. (abs(z) < zmax))
    z = func(z)
...

to

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)
...

This works fine for me, and gives the correct answer. 这对我来说很好,并给出了正确的答案。 If you're happy with that, you can stop reading. 如果对此感到满意,可以停止阅读。 Below is how I worked out how to fix it. 以下是我如何解决该问题的方法。


As for why this happens, you need to run f2py like 至于为什么出现这种情况,你需要运行f2py

f2py -m modname -h iterate.pyf iterate.f90
f2py -c --debug --build-dir build iterate.pyf iterate.f90

Then we can debug the code using gdb python , and then 然后我们可以使用gdb python调试代码,然后

run -c "import iterate; iterate.iterate(1.0j, lambda x: 4.0 + x*x, 4.0, 256)"

(although by the sounds of it, you probably got about this far anyway). (尽管听起来如此,但您可能还是走了这么远)。 Doing this, we find it segfaults on the following line in build/src.linux-x86_64.3.4/iteratemodule.c (your directory might be different): 这样做,我们在build/src.linux-x86_64.3.4/iteratemodule.c (您的目录可能不同)的以下行中找到segfaults:

complex_double z=(*z_cb_capi);

z_cb_capi being 0x0 , hence the segfault. z_cb_capi0x0 ,因此存在段错误。 This appears in the Cython helper function that is actually called when func is called in the Fortran code. 这将出现在Cython帮助器函数中,该func在Fortran代码中调用func时实际上会被调用。 The function declaration appears just before the line above, and in the version where func is a function rather than a subroutine, it looks like the following mess: 函数声明出现在上一行的前面,在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) {

which is essentially one of: 本质上是以下之一:

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)

depending on whether or not F2PY_CB_RETURNCOMPLEX is defined. 取决于是否定义了F2PY_CB_RETURNCOMPLEX It appears that F2PY_CB_RETURNCOMPLEX never does get defined, because gdb reports the function as having the first definition, but it is being called as if it were the second. 似乎从未定义过F2PY_CB_RETURNCOMPLEX ,因为gdb报告该函数具有第一个定义,但正在像第二个定义一样被调用。 You can see this because return_value is set to the address of z in the Fortran code, and nothing ( NULL ) is passed to z_cb_capi . 您可以看到这是因为在Fortran代码中return_value设置为z的地址,并且没有任何( NULL )传递给z_cb_capi

So, that eventually leads us to the second way to fix this: pass -DF2PY_CB_RETURNCOMPLEX to f2py : 因此,最终导致我们采用第二种方法来解决此问题:将-DF2PY_CB_RETURNCOMPLEX传递给f2py

f2py -c -DF2PY_CB_RETURNCOMPLEX --debug --build-dir build iterate.pyf iterate.f90

This then compiles cb_func_in_iterate__user__routines in the second form, which means it does get called correctly. 然后以第二种形式编译cb_func_in_iterate__user__routines ,这意味着它确实被正确调用。

Now, I don't think you should have to do this, so I rather suspect this is a bug in f2py . 现在,我认为您不必执行此操作,因此我怀疑这是f2py的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM