簡體   English   中英

在f2py回調上出現segfault

[英]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

嘗試與任何python回調函數一起使用iterate時,出現Segmentation fault錯誤。 這是我得到的示例結果:

>>> 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 (您的目錄可能不同)的以下行中找到segfaults:

complex_double z=(*z_cb_capi);

z_cb_capi0x0 ,因此存在段錯誤。 這將出現在Cython幫助器函數中,該func在Fortran代碼中調用func時實際上會被調用。 函數聲明出現在上一行的前面,在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報告該函數具有第一個定義,但正在像第二個定義一樣被調用。 您可以看到這是因為在Fortran代碼中return_value設置為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的錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM