PyObject_Malloc中的Python Segfaults

时间:2014-10-12 22:23:14

标签: python segmentation-fault mod-wsgi

无论我尝试使用哪种版本的Python(2.7,3.2,3.4),我都会对这行代码产生一个段错误:

Program received signal SIGSEGV, Segmentation fault.
_PyObject_Malloc (ctx=0x0, nbytes=50) at Objects/obmalloc.c:1159
1159                if ((pool->freeblock = *(block **)bp) != NULL) {

我的应用程序是一个mod_wsgi应用程序,我在OpenSSL中使用C扩展(但我​​发现C扩展中没有错误,即使是使用vagrind)。我无法使用valgrind重现错误,但是valgrind会提供大量错误,这些错误不会被提供的python抑制文件抑制。例如:

==4800== Use of uninitialised value of size 8
==4800==    at 0xD95E42A: PyEval_EvalFrameEx (ceval.c:2430)
==4800==    by 0xD964614: PyEval_EvalCodeEx (ceval.c:3585)
==4800==    by 0xD8C092F: function_call (funcobject.c:632)
==4800==    by 0xD89411E: PyObject_Call (abstract.c:2067)
==4800==    by 0xD95FC23: PyEval_EvalFrameEx (ceval.c:4558)
==4800==    by 0xD964614: PyEval_EvalCodeEx (ceval.c:3585)
==4800==    by 0xD8C080E: function_call (funcobject.c:632)
==4800==    by 0xD89411E: PyObject_Call (abstract.c:2067)
==4800==    by 0xD95FC23: PyEval_EvalFrameEx (ceval.c:4558)
==4800==    by 0xD963BE0: PyEval_EvalFrameEx (ceval.c:4331)
==4800==    by 0xD963BE0: PyEval_EvalFrameEx (ceval.c:4331)
==4800==    by 0xD964614: PyEval_EvalCodeEx (ceval.c:3585)

我在这个特定的实例中使用mod_wsgi版本4.3.0和Python 3.4.2,但其他版本也失败了。它总是在if ((pool->freeblock = *(block **)bp) != NULL) {行。

2 个答案:

答案 0 :(得分:6)

使用错误的C扩展名崩溃CPython运行时非常非常容易。

引用计数中的一个非常小的错误或内存处理中的小损坏会使系统不稳定。实际的碰撞位置通常不会给出麻烦的真正原因提供任何可行的暗示,因为很多时候真正的碰撞发生在原因之后很久。

我不能多说valgrind错误,但我也会说扩展中没有valgrind错误并不意味着没有错误。例如,Valgrind不知道Python运行时的引用计数系统 - 引用计数中的小错误通常是崩溃的原因。此外,您在Python运行时中获得“未初始化的值”错误可能是因为存在引用计数错误。当C扩展创建这样的情况时,运行时代码会导致麻烦 - 原因不是在运行时,而是在扩展中,而不是。

我认为,如果没有看到C扩展,就无法进行进一步的诊断。您是自己实现扩展还是一些开源软件?广泛传播吗?

我会尝试缩小扩展功能,使用时会造成麻烦。如果幸运的话,可以使用一组特殊参数将其缩小为一个函数调用。也许作者可以帮助找到错误?

答案 1 :(得分:0)

我们的应用程序以相同的方式在3.5.2(Ubuntu 16)上运行崩溃,但在我们的案例中,我们的C代码仅通过PyGObject API与Python交互,并且我们从未直接操纵PyObject引用计数。

经过一些调试后,问题被确定为issue 26617,该问题已在3.5.3(和3.6.0及更高版本)中修复。此问题导致PyObject双重释放,这破坏了自由内存链并最终导致此特定损坏。