首页 > 解决方案 > 我的 Python 程序因“致命的 Python 错误:取消分配无”而崩溃。这个错误是什么意思?

问题描述

我一直在尝试找出从 C++ 编译的一些 Python 代码的问题(使用 swig)。

通过使用 python3-dbg(python 版本 3.8)执行 gdb 来检索以下信息。

Python 因此错误而崩溃:

Fatal Python error: deallocating None
Python runtime state: initialized

调用堆栈上的 python 代码有问题的行是:

value = self.get(name)

请注意, 的值name应该是一个有效的字符串。这里似乎没有什么可能导致问题,但它通常发生在处理同一组数据时。这行代码在故障前被执行了数百次。

堆栈跟踪中对 none_dealloc 的第一次调用在这里:

#26 0x000000000046ef6e in none_dealloc (ignore=<optimized out>) at ../Objects/object.c:1585
#27 0x00000000004706da in _Py_Dealloc (op=<optimized out>) at ../Objects/object.c:2215
#28 0x00000000004470e8 in _Py_DECREF (op=<optimized out>, lineno=430, filename=0x699244 "../Objects/frameobject.c") at ../Include/object.h:478
#29 frame_dealloc (f=0x25938d0) at ../Objects/frameobject.c:430
#30 0x00000000004706da in _Py_Dealloc (op=op@entry=0x25938d0) at ../Objects/object.c:2215
#31 0x00000000004e02e6 in _Py_DECREF (op=0x25938d0, lineno=4314, filename=0x6e3343 "../Python/ceval.c") at ../Include/object.h:478
#32 _PyEval_EvalCodeWithName (_co=0x7fdc678c0520, globals=<optimized out>, locals=locals@entry=0x0, args=<optimized out>, argcount=2, kwnames=0x0, kwargs=0x7fdc6468cf90, kwcount=<optimized out>, kwstep=1, defs=0x7fdc678bf6f8, defcount=1, kwdefs=0x0, closure=0x0, name=0x7fdc67d0c270, qualname=0x7fdc678c2280) at ../Python/ceval.c:4314

这让我很困惑,因为在 Python 3.8 中在 frameobject.c 430 处启动 dealloc 的 Python 代码是:

/* Kill all local variables */
valuestack = f->f_valuestack;
for (p = f->f_localsplus; p < valuestack; p++)
    Py_CLEAR(*p);

Py_CLEAR 的定义在尝试减少引用计数并可能释放指针之前检查 NULL。这怎么会导致任何类型的错误?当我查看调用堆栈中 op 或 _py_tmp 的值时,它读作“优化”。

#define Py_CLEAR(op)                            \
    do {                                        \
        PyObject *_py_tmp = _PyObject_CAST(op); \
        if (_py_tmp != NULL) {                  \
            (op) = NULL;                        \
            Py_DECREF(_py_tmp);                 \
        }                                       \
    } while (0)

这个错误是什么意思?我应该寻找什么?

标签: pythonswigfatal-errorpython-c-api

解决方案


None 是 Python 中一个特殊的全局对象。“deallocating None”错误的意思是“None”的引用计数已达到 0,并且 None 将被释放(AKA 删除)。这是一件坏事!

这可能意味着导入的 Python 模块中的一个用 C/C++ 编写的函数在没有首先调用 Py_INCREF(Py_None) 的情况下返回 Py_None。然后,当有人丢弃对 None 的引用时,错误会在看似随机的、无害的代码行中显示在其他地方,因为 None 上的引用计数现在太少了 1。有关更多信息,请参阅此问题:为什么在 C 中返回 Py_None 之前需要 Py_INCREF(Py_None)?


推荐阅读