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 值是否失败,并适当地处理它。
我是第一次接触 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 值是否失败,并适当地处理它。