我正在研究Opencog开源框架的Python绑定(bind),试图解决一些崩溃问题,但我遇到了崩溃问题:

PyObject * pyAtomSpace;

if (atomspace)
    pyAtomSpace = py_atomspace(atomspace);

从:

https://github.com/opencog/opencog/blob/master/opencog/cython/PythonEval.cc#L148

在最后一行崩溃的地方调用了cython例程,该例程用以下cython代码将C++对象与python对象包装在一起:
cdef api object py_atomspace(cAtomSpace *c_atomspace) with gil:
    cdef AtomSpace atomspace = AtomSpace_factory(c_atomspace)
    return atomspace

从:
https://github.com/opencog/opencog/blob/master/opencog/cython/opencog/atomspace_details.pyx#L407-410

崩溃是SIGSEGV:
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff6354b6f in opencog::PythonEval::getPyAtomspace (
    this=<optimized out>, atomspace=<optimized out>)
    at /home/opencog/src/opencog/opencog/cython/PythonEval.cc:160
#2  0x00007ffff6354dd7 in opencog::PythonEval::init (this=0x67eb60)
    at /home/opencog/src/opencog/opencog/cython/PythonEval.cc:103
#3  0x00007ffff635512e in opencog::PythonEval::instance (atomspace=0x62c300)
    at /home/opencog/src/opencog/opencog/cython/PythonEval.cc:226
#4  0x00007ffff7bb5a83 in opencog::CogServer::CogServer (this=0x62bd40)
    at /home/opencog/src/opencog/opencog/server/CogServer.cc:127
#5  0x00000000004141bb in TestCogServer::createInstance ()
    at /home/opencog/src/opencog/tests/cython/PythonModuleUTest.cxxtest:37
#6  0x00007ffff7bb2a4a in opencog::server (
    factoryFunction=0x4141a0 <TestCogServer::createInstance()>)
    at /home/opencog/src/opencog/opencog/server/BaseServer.cc:65
#7  0x0000000000416e51 in PythonModuleUTest::PythonModuleUTest (
    this=0x6216f0 <suite_PythonModuleUTest>)
    at /home/opencog/src/opencog/tests/cython/PythonModuleUTest.cxxtest:82

如何调试此崩溃?我尝试过使用汇编程序。首先,我在使用disassemble-next-line崩溃的行上设置一个断点。注意:我用routine替换了下面的opencog::PythonEval::getPyAtomspace(opencog::AtomSpace*):
Breakpoint 1, opencog::PythonEval::getPyAtomspace (this=0x67eb50,
    atomspace=0x62c2f0)
    at /home/opencog/src/opencog/opencog/cython/PythonEval.cc:160
160         pyAtomSpace = py_atomspace(atomspace);
=> 0x00007ffff6354b66 <routine+6>:  48 89 f7    mov    %rsi,%rdi
   0x00007ffff6354b69 <routine+9>:  ff 15 29 69 20 00   callq  *0x206929(%rip)        # 0x7ffff655b498 <_ZL40__pyx_f_7opencog_9atomspace_py_atomspace>
   0x00007ffff6354b6f <routine+15>: 48 89 c3    mov    %rax,%rbx

callq之前的寄存器:
(gdb) info registers
rax            0x1c 28
rbx            0x67eb50 6810448
rcx            0x7ffff7716320   140737344791328
rdx            0x68 104
rsi            0x62c2f0 6472432
rdi            0x67eb50 6810448
rbp            0x7fffffffe790   0x7fffffffe790
rsp            0x7fffffffe780   0x7fffffffe780
r8             0x0  0
r9             0x9b57b0 10180528
r10            0x7fffffffe550   140737488348496
r11            0x7ffff6354b60   140737324075872
r12            0x7ffff7b8b140   140737349464384
r13            0x0  0
r14            0x62c2f0 6472432
r15            0x62bf01 6471425
rip            0x7ffff6354b66   0x7ffff6354b66 <opencog::PythonEval::getPyAtomspace(opencog::AtomSpace*)+6>
eflags         0x206    [ PF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0

看起来callq是使用%rip寄存器的寄存器相对调用,其值是0x7ffff6354b66且偏移量是0x206929
(gdb) disas /r 0x7ffff6354b66+0x206929,+10
Dump of assembler code from 0x7ffff655b48f to 0x7ffff655b499:
   0x00007ffff655b48f <_ZN7opencog10PythonEval17singletonInstanceE+7>:  00 01   add    %al,(%rcx)
   0x00007ffff655b491 <_ZZN7opencog10PythonEval4initEvE19eval_already_inited+0>:    01 00   add    %eax,(%rax)
   0x00007ffff655b493:  00 00   add    %al,(%rax)
   0x00007ffff655b495:  00 00   add    %al,(%rax)
   0x00007ffff655b497:  00 00   add    %al,(%rax)
End of assembler dump.

和原始内存转储:
(gdb) x/10 0x7ffff6354b66+0x206929
0x7ffff655b48f <_ZN7opencog10PythonEval17singletonInstanceE+7>: 0x00010100  0x00000000  0x00000000  0x00000000
0x7ffff655b49f <_ZL40__pyx_f_7opencog_9atomspace_py_atomspace+7>:   0x6213f000  0x00000000  0x6213f800  0x00000000
0x7ffff655b4af <_ZN5boost4asio5errorL17addrinfo_categoryE+7>:   0x62140000  0x00000000

然后使用si一步:
(gdb) si
0x00007ffff6354b69  160         pyAtomSpace = py_atomspace(atomspace);
   0x00007ffff6354b66 <routine+6>:  48 89 f7    mov    %rsi,%rdi
=> 0x00007ffff6354b69 <routine+9>:  ff 15 29 69 20 00   callq  *0x206929(%rip)        # 0x7ffff655b498 <_ZL40__pyx_f_7opencog_9atomspace_py_atomspace>
   0x00007ffff6354b6f <routine+15>: 48 89 c3    mov    %rax,%rbx
(gdb) si
[2015-02-24 01:43:14:072] [INFO] PythonEval atomspace 1
0x0000000000000000 in ?? ()
=> 0x0000000000000000:  Cannot access memory at address 0x0

我不确定在上述所有情况下,零解引用来自何处,但是我从来没有精通Linux上的X86汇编器。

加载包含它的动态库时,它的作用就像cython代码未正确链接。或者其他的东西?知道为什么调用py_atomspace cython例程会导致此崩溃吗?我在上面缺少明显的东西吗?还是弄错了?

我还应该提到,上面的代码在很多情况下都可以正常工作,直到我更改了一些初始化Python的方式后,我才得到上面的崩溃。因此,我试图弄清楚我的更改可能如何影响此调用,因为我未对cython代码py_atomspace或py_atomspace的调用者进行任何更改。

最佳答案

事实证明,即使您需要在一个地方初始化Python,也必须在许多地方初始化Cython。

在OpenCog的情况下,您需要调用Cython生成的导入函数:

import_opencog__atomspace();


import_opencog__agent_finder();

每个共享库中的,它调用Cython代码中声明为“api”的函数。否则,在该共享库中对该函数的第一次调用时会崩溃。正如您在上面看到的,SIGSEGV没有留下有用的堆栈跟踪。只是两个汇编指令和动臂,即注册相对的callq段。您知道它在api调用中崩溃了,是的,但是当您确认确实在调用import函数时,您只是单步执行,它仍然崩溃。仅仅调用它还不够,您需要在该共享库中调用它。

Cython文档完全没有提到这一点(至少在我提交请求以解决该问题之前)。

关于c++ - 从C++调用的Cython代码中的调试崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28687248/

10-11 14:00
查看更多