Windows 下 Python 3 出现 segfault 时如何定位和调试?

请教各位在 Windows 下 Python 3 出 segfault 时如何有效地找错。

Linux 下有 gdb。Windows 下 MinGW 的 gdb-python 好像只能用在 Python 2 上。我的程序是用 Python 3 写的,很多自己写的函数,2to3 应付不了,手动改要花很多时间。有在 qq 群里问过,有人建议用二分法删源码,直到 segment fault 不再出现就找到错了。这种方法好像效率太低,而且如果 segment fault 不是固定出现在某的地方不可用。

GUI 下用个 thread、pubsub 什么的,出 segfault 还是比较常见的,而且 GUI ( pyqt,wxpython 之类的)程序的 Test 测试好像也没有什么好的办法,unitest、pytes 派不太上用场。各路高手用什么方法找导致 segfault 的错误?请分享一下,先感谢。


Windows 下 Python 3 出现 segfault 时如何定位和调试?

21 回复

完整的错误信息贴出来看看。


在Windows下调试Python的段错误(segfault)确实比较棘手,因为标准的Python调试工具对这类底层错误帮助有限。核心思路是让解释器在崩溃时生成更多信息供分析。

最直接有效的方法是使用faulthandler模块。在程序开头启用它,可以将崩溃时的Python堆栈跟踪打印到标准错误流或指定文件。

import faulthandler
import sys

# 启用faulthandler,将崩溃信息输出到stderr
faulthandler.enable()

# 或者将崩溃信息写入文件(推荐,避免输出丢失)
with open('crash.log', 'w') as f:
    faulthandler.enable(file=f)

# 你的代码从这里开始...
# 模拟一个会导致segfault的C扩展调用(示例)
# import some_faulty_extension
# some_faulty_extension.crash()

如果程序不是从命令行启动的(比如GUI应用),将日志写入文件至关重要。faulthandler在Python 3.3及以上版本是标准库的一部分。

另一个强力工具是使用gdb(通过Cygwin或WSL安装)来运行Python解释器。这能获得最底层的调用堆栈:

gdb python
(gdb) run your_script.py
# 崩溃后
(gdb) backtrace

backtrace命令会显示C级别的完整调用堆栈,帮你精确锁定是哪个Python C扩展模块、标准库的C实现,还是解释器本身出了问题。大部分Windows下的Python segfault都源于有bug的C扩展(比如某些用Cython或C/C++写的包),或者是与特定DLL的冲突。

总结:先用faulthandler抓Python堆栈,再用gdb抓C堆栈定位根本原因。

出 segfault 是没有错误信息的,整个 python 死掉。

Python 出 Segment Fault 一般不是 Python 写的代码的问题。

你写的、或者你引用的 native package 有问题。删掉整个 Python 3 重新安装一下吧?另外二进制的包如果用 Anaconda 装,一般会降低出问题的概率。

gdb --args ./app … 跑一遍, 出了 segment fault, 用 bt 命令, 输出 stack trace

感谢楼上 、 二位。

不管是 native package 还是代码问题,都是想先找到出错的原因。gdb 貌似不能给出出错的 python 源码位置。看 stackoverflow 里说,gdb-python 倒是可以给出 python 源码位置。但 gdb-python 在 windows 里只能用于 Python 2. 我已经花了一天试着将我的 Python 3 改成 Python 2. 太麻烦、太乱,只好放弃。

#5 用 VS 来编译 Python,然后参数加上你要运行的 Python 代码,应该可以定位到错误位置。

感谢。先记下来研究一下。VS 好像太大了,而且我的机器比较旧,怕是拖不动 VS。

你把你装的依赖包列一下我们看看吧。很可能某个第三方库的二进制包和你的 Python 二进制不太兼容…… 或者你的代码使用第三方库时导致了它内部二进制包的异常。

另外最后的出错信息打出来看看也很重要。第三方库的二进制包出问题的 stack trace 和 Python 自己的二进制包出错,信息还是不一样的。

gdb-python 可以用于 python 3,不过你得自己编译安装。我试过,挺麻烦

感谢提供信息。我想我会用 MinGW 试试。如果你有有关资料能提供一些链接什么的就更加感谢了。

certifi==2017.4.17
chardet==3.0.2
colorama==0.3.9
configobj==5.0.6
cx-Freeze==5.0.2
future==0.16.0
googletrans==2.1.3
html2text==2016.9.19
langdetect==1.0.7
langid==1.1.6
lxml==3.7.3
nltk==3.2.2
nose==1.3.7
numpy==1.13.0
pandas==0.20.2
py==1.4.34
pycountry==17.1.8
pysrt==1.1.1
pysubs2==0.2.1
pytest==3.1.2
python-dateutil==2.6.0
python-docx==0.8.6
pytz==2017.2
pywin32==221
PyYAML==3.12
regex==2017.4.29
requests==2.13.0
requests-cache==0.4.13
segtok==1.5.5
six==1.10.0
textblob==0.12.0
tqdm==4.11.2
wxPython==4.0.0a2.dev3016+2645796
xlrd==1.0.0
yandex.translate==0.3.5

Python 3.5 venv 下 pip freeze 的包

因为看不懂 stack trace,所以一直在整 gdb-python,不过我试着用 gdb 在 Python 3 下获取 stack trace,成功的话在贴上来。

用 WinDBG 跑 Python,挂了之后输入 k 看一下调用栈,一般就知道是哪个库的问题了。如果问题不复杂,这可能是最快的方法。

感谢。我试试……

https://github.com/fedora-python/python3/blob/master/python-gdb.py
https://wiki.python.org/moin/DebuggingWithGdb
https://docs.python.org/devguide/gdb.html
你需要单独编译 gdb 和 CPython。编译 gdb 的时候,加–with-python="${the directory in which your python3 binary is installed}"。编译一份 CPython,记得用 debug 模式,这样调试时 step 到标准库,也会显示源码的

库我认不全,不过我认知的库里面,NumPy, wxPython 和 lxml 都有 native binary。也许应该注意一下。

貌似 Windows 下 Python 3 要找 segfault 出错的地方没有什么办法。再加上我的程序还是 wxpython GUI,完全没辙。我试过 Windbg,winpdb,trepan3k,pudb, 都不行。

Windbg 里用 pykd 可以运行 python 非 GUI 程序,运行 wxpython 写的 gui 程序就出不来 gui。也可以在 python 下运行 wxpython 写的 gui 程序后 attach 到 Windbg, 但 attach 后 wxpython gui 就没有反应了, 也就是说没法 gui 里的交互(点击、载入文件啊什么的)。

最后还是靠 logging …… 找到 python 一个 bug:

os.startfile("")

python ( 2.7, 3.4, 3.5 )直接死掉。try… except … 没有用…… 花掉我一整天 ……&¥……%¥#

” Windbg 里用 pykd 可以运行 python 非 GUI 程序,运行 wxpython 写的 gui 程序就出不来 gui。“

这个尝试完全是晕了头. pykd 是 windbg 的一个插件. 在 windbg 里跑起来一个 python vm, 用来和 windbg 交互. 和 op 现在遇到的 python crash 八杆子打不着.

这个 os.startfile("") 导致 python.exe 崩溃其实只在 ConEmu 下才出现(我的是 32 位 Windows 7,ConEmu 161002 ),所以可能要算 ConEmu 的 bug 吧……

感谢回答。

我搞不太清楚。不过 Windbg 里 如果不 !load pykd.dll 是运行不了 !py 的。

Windbg 里 Alt-1:
0:000> !py -3.4
No export py found
0:000> !load pykd.dll
0:000> !py -3.4
Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)] on win32
Type “help”, “copyright”, “credits” or “license” for more information.
(InteractiveConsole)
>>>

segfault 报错很多是 C 扩展不支持多线程操作, 比如多线程对一个 mysql(mysqldb)连接发起查询请求就会这样(每个线程开一个连接去查询就可以解决这个问题)。 大部分是 C 扩展一个回话不支持多线程操作 或者操作需要加锁

回到顶部