python跟踪分段错误

python跟踪分段错误,python,c,debugging,Python,C,Debugging,我正在从python开发C扩展,我得到了一些错误(在开发过程中不可避免…) 我正在寻找一种方法来显示segfault发生在哪一行代码上(一种想法就像跟踪每一行代码),我如何才能做到这一点?下面是一种方法,可以输出代码运行的每一行Python的文件名和行号: import sys def trace(frame, event, arg): print("%s, %s:%d" % (event, frame.f_code.co_filename, frame.f_lineno))

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


我正在寻找一种方法来显示segfault发生在哪一行代码上(一种想法就像跟踪每一行代码),我如何才能做到这一点?

下面是一种方法,可以输出代码运行的每一行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

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

如果您在linux上,请在gdb下运行python

gdb python
(gdb) run /path/to/script.py
## wait for segfault ##
(gdb) backtrace
## stack trace of the c code

来自C扩展的SEGFULT通常是由于在创建对象的新引用时未增加引用计数而导致的。这使得它们很难跟踪,因为segfault仅在从对象中删除最后一个引用之后发生,甚至通常只有在分配其他对象时才会发生

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


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

gdb有一些未记录的Python扩展

从Python源代码抓取(它不包括在正常安装中)

将其放入
sys.path

然后:

这方面的文档记录得有点少,以及


如果您有一个较旧的
gdb
或者就是无法实现这一点,那么Python源代码中也有一个可以复制到
~/.gdbinit
,它添加了一些类似的功能

我来这里是为了寻找同一问题的解决方案,而其他答案都没有帮助我。帮助的是,您可以使用
pip install
在Python2.7中安装它


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

如果您已经有了核心文件,您可以使用
gdb Python core
(或任何核心文件的名称)。如果您在OSX上,内核转储(默认情况下不生成;请参阅
ulimit-c
)存储在目录
/cores
中。我真希望这是我的第一个答案,因为阅读所有其他内容花费了相当长的时间,我宁愿花在查找我的bug上。如果在运行Python单元测试时遇到SEGFULT,如
Python-m unittest my.module.tests.mytest
,则,然后
-m
开关会混淆
gdb
。使用
--args
选项调用:
gdb--args python-m unittest my.module.tests.mytest
类似地使用命令:`gdb--args python3.6-c“import something;something.doStuff();”@标记您的答案对我很有帮助,谢谢!它只是说“没有指定可执行文件”@MadPhysicast:它不会打印C代码的行号,如果这是你的意思的话。:-)它将打印调用C代码的Python代码的行号,这就是我的意思。我发现原来的问题很有趣,因为我也有同样的问题。segfault原来是因为我的C代码在PyList_对象中插入了NULL元素。当我尝试遍历列表时,它在Python端表现出来。不确定python调试器在这种情况下会有多大帮助。为了使输出更易于阅读(并且不会显著降低程序的速度),请使用中提到的
faulthandler
模块)--但即使要使用跟踪,也只需使用python的内置跟踪模块(
python-m trace--trace test.py
)--但是,这两种方法都不会在C代码中显示回溯。而且,在不属于它们的地方放置空值。很好!若您可以读取Python程序的标准输出,那个么使用起来就像:
importfaulthandler;faulthandler.enable()
# 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):
(gdb) python
>import sys
>sys.path.append('/path/to/containing/dir/')
>import libpython
>
>end