c-跟踪分段fau的python

我正在从python ad开发C扩展,我得到了一些段错误(在开发过程中不可避免...)。

我正在寻找一种方法来显示段错误发生在哪一行代码(一个想法就像跟踪每一行代码),我该怎么做?

pygabriel asked 2020-02-29T09:46:47Z
5个解决方案
69 votes

如果您使用的是Linux,请在gdb下运行python

gdb python
(gdb) run /path/to/script.py
## wait for segfault ##
(gdb) backtrace
## stack trace of the c code
Mark answered 2020-02-29T09:47:29Z
38 votes

这是一种输出代码运行的Python每行的文件名和行号的方法:

import sys

def trace(frame, event, arg):
    print "%s, %s:%d" % (event, frame.f_code.co_filename, frame.f_lineno)
    return trace

def test():
    print "Line 8"
    print "Line 9"

sys.settrace(trace)
test()

输出:

call, test.py:7
line, test.py:8
Line 8
line, test.py:9
Line 9
return, test.py:9

(当然,您可能希望将跟踪输出写入文件。)

RichieHindle answered 2020-02-29T09:47:09Z
17 votes

来自C扩展的段错误通常是在创建对对象的新引用时未增加引用计数的结果。 这使得它们非常难追踪,因为段错误仅在从对象中删除最后一个引用之后才发生,即使在分配其他对象时也经常发生。

您不会说到目前为止已经写了多少C扩展代码,但是如果您刚开始,请考虑可以使用ctypes还是Cython。 Ctypes可能不够灵活,无法满足您的需求,但是您应该能够使用Cython链接到几乎任何C库,并自动为您维护所有引用计数。

这并不总是足够的:如果您的Python对象和任何底层C对象具有不同的生存期,您仍然会遇到问题,但确实可以大大简化事情。

Duncan answered 2020-02-29T09:47:59Z
7 votes

我是来这里寻找相同问题的解决方案的,其他答案都没有帮助我。 帮助的是faulthandler,您可以仅使用faulthandler将其安装在Python 2.7中。

faulthandler仅在版本3.3中引入Python,该版本于2012年9月发布,这是在编写了大多数其他答案之后进行的。

mariotomo answered 2020-02-29T09:48:24Z
3 votes

gdb有一些未公开的python扩展。

从Python源码中获取gdb(普通安装中不包括)。

把它放在gdb

然后:

# gdb /gps/python2.7_x64/bin/python coredump
...
Core was generated by `/usr/bin/python script.py'.
Program terminated with signal 11, Segmentation fault.
#0  call_function (oparg=<optimized out>, pp_stack=0x7f9084d15dc0) at Python/ceval.c:4037
...
(gdb) python
>import libpython
>
>end
(gdb) bt
#0  call_function (oparg=<optimized out>, pp_stack=0x7f9084d15dc0) at Python/ceval.c:4037
#1  PyEval_EvalFrameEx (f=f@entry=
    Frame 0x7f9084d20ad0, 
    for file /usr/lib/python2.7/site-packages/librabbitmq/__init__.py, line 220, 
    in drain_events (self=<Connection(channels={1: <Channel(channel_id=1, connection=<...>, is_open=True, connect_timeout=4, _default_channel=<....(truncated), throwflag=throwflag@entry=0) at Python/ceval.c:2681
...
(gdb) py-list
 218            else:
 219                timeout = float(timeout)
>220            self._basic_recv(timeout)
 221
 222        def channel(self, channel_id=None):

如您所见,我们现在可以看到与CPython调用链相对应的Python堆栈。

一些警告:

  • 您的gdb版本必须大于7,并且必须使用gdb进行编译
  • gdb嵌入python(通过链接到~/.gdbinit),它没有在子shell中运行。 这意味着它不一定与sys.path上的python版本匹配。
  • 您需要从与~/.gdbinit所链接的内容相匹配的任何Python源版本中下载gdb
  • 您可能必须以root用户身份运行gdb-如果这样,则可能需要设置gdb以匹配要调试的代码。

如果无法将gdb复制到~/.gdbinit,则可以将其位置添加到sys.path,如下所示:

(gdb) python
>import sys
>sys.path.append('/path/to/containing/dir/')
>import libpython
>
>end

在python dev docs,fedora Wiki和python Wiki中很少对此进行记录

如果您有较旧的gdb或无法正常工作,则Python源代码中还有一个gdbinit,您可以将其复制到~/.gdbinit,这会添加一些类似的功能

scytale answered 2020-02-29T09:49:38Z
translate from https://stackoverflow.com:/questions/2663841/python-tracing-a-segmentation-fault