Python C 扩展段错误

Python C extension segfault

我是第一次接触 C 扩展,对 C 也有些陌生。我有一个可用的 C 扩展,但是,如果我在 python 中重复调用该实用程序,我最终会遇到分段错误:11.

#include <Python.h>

static PyObject *getasof(PyObject *self, PyObject *args) {
    PyObject *fmap;
    long dt;

    if (!PyArg_ParseTuple(args, "Ol", &fmap, &dt))
        return NULL;

    long length = PyList_Size(fmap);

    for (int i = 0; i < length; i++) {
        PyObject *event = PyList_GetItem(fmap, i);
        long dti = PyInt_AsLong(PyList_GetItem(event, 0));
        if (dti > dt) {
             PyObject *output = PyList_GetItem(event, 1);
            return output;
        }
    }
    Py_RETURN_NONE;
 };

函数参数是 时间序列(列表列表):ex [[1, 'a'], [5, 'b']] 时间(长):ex 4

它应该遍历列表的列表,直到它找到一个大于给定时间的值。然后 return 该值。正如我提到的,它正确 return 是答案,但如果我调用它的次数足够多,它就会出现段错误。

我的直觉是这与引用计数有关,但我对这个概念不够熟悉,不知道这是否是直接原因。

如有任何帮助,我们将不胜感激。

"My gut feeling is that this has to do with reference counting..."你的直觉是正确的。

PyList_GetItem return 是 借来的 引用,这意味着您的函数没有 "own" 对项目的引用。所以这里有问题:

        PyObject *output = PyList_GetItem(event, 1);
        return output;

您不拥有对该项目的引用,但您 return 将其提供给调用者,因此调用者也不拥有引用。如果在调用者仍在尝试使用它时项目被垃圾收集,调用者将 运行 陷入问题。因此,您需要在 return 之前增加项目的引用计数:

        PyObject *output = PyList_GetItem(event, 1);
        Py_INCREF(output);
        return output;

假设 PyList_GetItem(event, 1) 不会失败!除了 PyArg_ParseTuple,您没有检查 C API 函数的 return 值,这意味着您假设输入参数始终具有您期望的确切结构。这在您测试代码并弄清楚其工作原理时很好,但最终您应该检查 C API 函数的 return 值是否失败,并适当地处理它。