通过tp_getset访问时出现Python C扩展错误

通过tp_getset访问时出现Python C扩展错误,python,c,segmentation-fault,python-c-api,Python,C,Segmentation Fault,Python C Api,我正在尝试为python编写一个C扩展。我想写的是一个modpolymone类,它表示(Z/nZ)[x]/x^r-1]上的一个多项式[尽管你可能回答我的问题,但对这些多项式一无所知] 我已经写了一些代码,看起来很有效。基本上我只在ModPoly结构中存储三个PyObject*。现在我想为多项式的系数添加存储 因为我希望系数是只读的,所以我想通过PyGetSetDef添加一对getter/setter函数。但是当我从python访问getter时(例如printpol.coverties),我收到

我正在尝试为python编写一个C扩展。我想写的是一个modpolymone类,它表示(Z/nZ)[x]/x^r-1]上的一个多项式[尽管你可能回答我的问题,但对这些多项式一无所知]

我已经写了一些代码,看起来很有效。基本上我只在ModPoly结构中存储三个PyObject*。现在我想为多项式的系数添加存储

因为我希望系数是只读的,所以我想通过PyGetSetDef添加一对getter/setter函数。但是当我从python访问getter时(例如printpol.coverties),我收到了一个分段错误

可以找到没有“系数”的原始代码。 具有系数的代码为

我希望你们中有人能告诉我哪里做错了。 顺便说一下,也欢迎对代码发表评论。这是我的第一次扩展,我知道我可能做得很糟糕

正如ecatmur在注释中所说,PyVarObject在结构的末尾存储一定数量的“插槽”。所以我决定避开他们

有关守则如下:

typedef struct {
    PyObject_HEAD
    /* Type specific fields */

    Py_ssize_t ob_size;
    PyObject **ob_item;
    Py_ssize_t allocated;

    PyObject *r_modulus;
    PyObject *n_modulus;
    PyObject *degree;
} ModPoly;



static PyObject *
ModPoly_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    ModPoly *self;

    self = (ModPoly *)type->tp_alloc(type, 0);
    if (self != NULL) {
        [...]

        self->ob_size = 0;
        self->ob_item = NULL;
        self->allocated = 0;
    }

    return (PyObject *)self;
}


static int
ModPoly_init(ModPoly *self, PyObject *args, PyObject *kwds)
{
    PyObject *r_modulus=NULL, *n_modulus=NULL, *coefs=NULL, *tmp;
    PyObject **tmp_ar;

    static char *kwlist[] = {"r_modulus", "n_modulus", "coefficients", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist,
                                     &r_modulus, &n_modulus, &coefs))
        return -1;

    [...]

    // The polynomial defaults to "x", so the coefficients should be [0, 1].
    tmp_ar = (PyObject **)malloc(2 * sizeof(PyObject*));
    if (tmp_ar == NULL) {
        Py_DECREF(self->r_modulus);
        Py_DECREF(self->n_modulus);
        Py_DECREF(self->degree);
        return -1;
    }

    tmp_ar[0] = PyInt_FromLong(0);
    if (tmp_ar[0] != NULL) {
        tmp_ar[1] = PyInt_FromLong(1);
    }

    if (tmp_ar[0] == NULL || tmp_ar[0] == NULL) {
        Py_DECREF(self->r_modulus);
        Py_DECREF(self->n_modulus);
        Py_DECREF(self->degree);
        Py_XDECREF(tmp_ar[0]);
        Py_XDECREF(tmp_ar[1]);
        free(tmp_ar);
        return -1;
    }

    self->ob_size = 2;
    self->allocated = 2;

    return 0;
}

[...]

static PyObject *
ModPoly_getcoefs(ModPoly *self, void *closure)
{
    printf("here"); // "here" is never printed
    PyTupleObject *res=(PyTupleObject*)PyTuple_New(self->ob_size);
    Py_ssize_t i;
    PyObject *tmp;

    if (res == NULL)
        return NULL;

    for (i=0; i < self->ob_size; i++) {
        tmp = self->ob_item[i];
        Py_INCREF(tmp);
        PyTuple_SET_ITEM(res, i, tmp);
    }
    return (PyObject *)res;
}

static PyObject *
ModPoly_setcoefs(ModPoly *self, PyObject *value, void* closure)
{
    PyErr_SetString(PyExc_AttributeError,
                    "Cannot set the coefficients of a polynomial.");
    return NULL;
}

[...]

static PyGetSetDef ModPoly_getsetters[] = {
  {"coefficients",
      (getter)ModPoly_getcoefs, (setter)ModPoly_setcoefs,
    "The polynomial coefficients.", NULL},
  {NULL, 0, 0, NULL, NULL}  
};


static PyTypeObject ModPolyType = {
    PyObject_HEAD_INIT(NULL)
        0,                                                                      /* ob_size        */
    [...]
    ModPoly_members,                                        /* tp_members */
    ModPoly_getsetters,                                     /* tp_getset */
    0,                                                      /* tp_base */
    [...]
};

[...]
typedef结构{
皮尤头
/*类型特定字段*/
Py_-ssize_t ob_尺寸;
PyObject**ob_项;
分配的资源;
PyObject*r_模;
PyObject*n_模;
PyObject*度;
}ModPoly;
静态PyObject*
ModPoly_new(PyTypeObject*type,PyObject*args,PyObject*kwds)
{
ModPoly*self;
self=(ModPoly*)类型->tp_alloc(类型,0);
if(self!=NULL){
[...]
self->ob_size=0;
self->ob_item=NULL;
自->分配=0;
}
返回(PyObject*)self;
}
静态整数
ModPoly_init(ModPoly*self、PyObject*args、PyObject*kwds)
{
PyObject*r_模数=NULL,*n_模数=NULL,*coefs=NULL,*tmp;
PyObject**tmp\u ar;
静态字符*kwlist[]={“r_模”、“n_模”、“系数”,NULL};
如果(!PyArg|u ParseTupleAndKeywords(args,kwds,“OO | O”,kwlist,
&r_模量和n_模量和系数)
返回-1;
[...]
//多项式默认为“x”,因此系数应为[0,1]。
tmp_ar=(PyObject**)malloc(2*sizeof(PyObject*);
if(tmp_ar==NULL){
Py_DECREF(自->r_模量);
Py_DECREF(自->n_模量);
Py_DECREF(自->度);
返回-1;
}
tmp_ar[0]=PyInt_FromLong(0);
如果(tmp_ar[0]!=NULL){
tmp_ar[1]=PyInt_FromLong(1);
}
if(tmp_ar[0]==NULL | | tmp_ar[0]==NULL){
Py_DECREF(自->r_模量);
Py_DECREF(自->n_模量);
Py_DECREF(自->度);
Py_XDECREF(tmp_ar[0]);
Py_XDECREF(tmp_ar[1]);
免费(tmp_ar);
返回-1;
}
self->ob_size=2;
自->分配=2;
返回0;
}
[...]
静态PyObject*
ModPoly_getcoefs(ModPoly*self,void*closure)
{
printf(“此处”);/“此处”从不打印
PyTupleObject*res=(PyTupleObject*)PyTuple\u New(self->ob\u size);
Py_ssize_t i;
PyObject*tmp;
如果(res==NULL)
返回NULL;
对于(i=0;iob\u size;i++){
tmp=self->ob_项目[i];
Py_增量(tmp);
PyTuple_SET_项(res、i、tmp);
}
返回(PyObject*)res;
}
静态PyObject*
ModPoly_setcoefs(ModPoly*self,PyObject*value,void*closure)
{
PyErr_设置字符串(PyExc_属性错误,
“不能设置多项式的系数。”);
返回NULL;
}
[...]
静态PyGetSetDef ModPoly_getsetters[]={
{“系数”,
(getter)ModPoly_getcoefs,(setter)ModPoly_setcoefs,
“多项式系数”,NULL},
{NULL,0,0,NULL,NULL}
};
静态PyTypeObject ModPolyType={
PyObject\u HEAD\u INIT(空)
0,/*ob_尺寸*/
[...]
ModPoly_成员,/*tp_成员*/
ModPoly_getsetters,/*tp_getset*/
0,/*tp_基*/
[...]
};
[...]
编辑

我试图一个接一个地重新实现getter指令,我明白我没有做什么。在ModPoly_init函数中,我创建了tmp_ar,在那里我存储了系数,但我没有将其分配给self->ob_项


-facepalm-

您似乎只是在
ModPoly\u new()
中分配给
ModPoly.ob\u项(将其设置为
NULL


ModPoly_getcoefs()
然后取消对空指针的引用,这将给出您的错误。看起来您打算在
ModPoly_init()
中分配
ob_项
,但实际上并没有这样做。

未使用标题的ob_大小字段;它在类型结构中的存在是一个历史工件,为了与为较早版本的Python编译的扩展模块保持二进制兼容性。始终将此字段设置为零。请在你的问题中内联发布你的代码(删除任何不必要的代码)。哦,我忘了那个注释。但这是否意味着PyVarObjects已经过时?阅读python2.7.3的源代码,我可以看到它仍然被列表类型使用。VAR与普通HEAD宏之间的区别是什么?VAR对象以一个包含1个元素的数组声明结尾,但为对象末尾的
n
元素分配了足够的内存。您几乎可以肯定不需要使用它们。如果您了解Python和C,您可以使用编写C扩展。它在不同的Python版本之间更好、更可移植。