PyObject_Malloc中的Python分段错误



无论我尝试哪种版本的Python(2.7、3.2、3.4),我都会在这行代码上得到一个segfault:

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扩展(但即使使用vagrind,我也没有看到C扩展中的错误)。我无法用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) {线上。

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

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

我不能对valgrind错误说太多,但我也要说,扩展中没有valgrind误差并不意味着没有错误。例如,Valgrind不知道Python运行时的引用计数系统,而引用计数中的小错误往往是崩溃的原因。此外,在Python运行时中出现"未初始化值"错误的原因可能是存在引用计数错误。当C扩展造成这种情况时,运行时代码肯定会陷入麻烦——原因不在运行时,而是在扩展中。

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

我会尽量缩小扩展的功能范围,当使用时,会造成麻烦。如果幸运的话,它可以缩小到一个带有一组特殊参数的函数调用。也许作者可以帮助找出错误?

我们的应用程序以同样的方式在3.5.2(Ubuntu16)上运行时崩溃,但在我们的情况下,我们的C代码仅通过PyGObject API与Python交互,我们从未直接操纵PyObject引用计数。

经过一些调试,问题被确定为问题26617,该问题在3.5.3(以及3.6.0及更高版本)中得到了修复。这个问题会导致PyObject的双重释放,从而破坏可用内存链,并最终导致这种特定的损坏。

最新更新