Warum ist diese Speicherzugriffsfehler C-Methode?
-
27-09-2019 - |
Frage
Ich schreibe eine unveränderliche verknüpfte Liste Klasse in C, aber ein Verfahren ist auf mysteriöse Weise Speicherzugriffsfehler. Der Code soll in etwa entspricht dies sein:
class PList(object):
def __init__(self, first, rest=None):
self.first = first
self.rest = rest
def cons(self, item):
return PList(item, self)
Hier ist mein Code:
#include <Python.h>
#include <structmember.h>
static PyTypeObject PListType;
typedef struct PListStruct{
PyObject_HEAD
PyObject *first;
struct PListStruct *rest;
} PList;
static PyMemberDef plist_members[] = {
{"first", T_OBJECT_EX, offsetof(PList, first), READONLY, "First element"},
{"rest", T_OBJECT_EX, offsetof(PList, rest), READONLY, "Rest of the list"},
{NULL}
};
static PyObject *
PList_cons(PList *self, PyObject *arg)
{
PList *new_list = PyObject_CallFunctionObjArgs(&PListType, arg, self);
Py_INCREF(new_list);
return new_list;
}
static PyMethodDef plist_methods[] = {
{"cons", (PyCFunction)PList_cons, METH_O, "Add an item to the list"},
{NULL}
};
static void PList_dealloc(PList *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->rest);
self->ob_type->tp_free((PyObject*)self);
}
static int
PList_init(PList *self, PyObject *args, PyObject *kwds)
{
PyObject *first=NULL, *rest=NULL, *tmp;
static char *kwlist[] = {"first", "rest", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
&first, &rest))
return -1;
if (first){
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (rest) {
tmp = self->rest;
Py_INCREF(rest);
self->rest = rest;
Py_XDECREF(tmp);
}
else {
tmp = self->rest;
Py_INCREF(Py_None);
self->rest = Py_None;
Py_XDECREF(tmp);
}
return 0;
}
static PyTypeObject PListType= {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"pysistence.persistent_list.PList", /*tp_name*/
sizeof(PList), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)PList_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"Persistent list", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
plist_methods, /* tp_methods */
plist_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PList_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initpersistent_list(void)
{
PyObject *m;
PListType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PListType) < 0)
return;
m = Py_InitModule3("pysistence.persistent_list", 0,
"Docstring");
Py_INCREF(&PListType);
PyModule_AddObject(m, "PList", (PyObject*)&PListType);
}
Wenn ich diesen Code ausführen, es Segfaults in der letzten Zeile:
from pysistence.persistent_list import PList
p = PList(1)
p = PList(2, p)
p = p.cons(3)
Ich bin sicher, ich mache nur etwas dumm, aber ich sehe nicht, was es ist. Gibt es etwas, was ich bin fehlt?
Lösung
Ich bin aus der Dokumentation zu lesen:
PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
Return value: New reference.
Rufen Sie eine aufrufbare Objekt aufrufbar Python, mit einer variablen Anzahl von PyObject * Argumente. Die Argumente werden bereitgestellt, wie eine variable Anzahl von Parametern von NULL gefolgt. Gibt das Ergebnis des Aufrufs auf Erfolg oder NULL bei einem Fehler.
Sie werden am Ende den NULL-Wert fehlen.
Edit: Ho, und Sie wollen auch, wenn die Funktion zurückgibt NULL bei Speicherfehler
überprüfen