I have a custom implementation of dict using a C extension. All works but
the pickling of views and iter types. Python segfaults if I try to pickle
them.

For example, I have:


static PyTypeObject PyFrozenDictIterKey_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "frozendict.keyiterator",                   /* tp_name */
    sizeof(dictiterobject),                     /* tp_basicsize */
    0,                                          /* tp_itemsize */
    /* methods */
    (destructor)dictiter_dealloc,               /* tp_dealloc */
    0,                                          /* tp_vectorcall_offset */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_as_async */
    0,                                          /* tp_repr */
    0,                                          /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    PyObject_HashNotImplemented,                /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
    0,                                          /* tp_doc */
    (traverseproc)dictiter_traverse,            /* tp_traverse */
    0,                                          /* tp_clear */
    0,                                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    PyObject_SelfIter,                          /* tp_iter */
    (iternextfunc)frozendictiter_iternextkey,   /* tp_iternext */
    dictiter_methods,                           /* tp_methods */
    0,
};

This is the backtrace I get with gdb:

#0  PyObject_Hash (v=0x7f043ce15540 <PyFrozenDictIterKey_Type>) at
../cpython_3_10/Objects/object.c:788
#1  0x000000000048611c in PyDict_GetItemWithError (op=0x7f043e1f4900,
key=key@entry=0x7f043ce15540 <PyFrozenDictIterKey_Type>)
    at ../cpython_3_10/Objects/dictobject.c:1520
#2  0x00007f043ce227f6 in save (self=self@entry=0x7f043d8507d0,
obj=obj@entry=0x7f043e1fb0b0, pers_save=pers_save@entry=0)
    at /home/marco/sources/cpython_3_10/Modules/_pickle.c:4381
#3  0x00007f043ce2534d in dump (self=self@entry=0x7f043d8507d0,
obj=obj@entry=0x7f043e1fb0b0) at
/home/marco/sources/cpython_3_10/Modules/_pickle.c:4515
#4  0x00007f043ce2567f in _pickle_dumps_impl (module=<optimized out>,
buffer_callback=<optimized out>, fix_imports=<optimized out>,
protocol=<optimized out>,
    obj=0x7f043e1fb0b0) at
/home/marco/sources/cpython_3_10/Modules/_pickle.c:1203
#5  _pickle_dumps (module=<optimized out>, args=<optimized out>,
nargs=<optimized out>, kwnames=<optimized out>)
    at /home/marco/sources/cpython_3_10/Modules/clinic/_pickle.c.h:619

and so on. The problematic part is in the second frame. Indeed the code of
_pickle.c here is:


        reduce_func = PyDict_GetItemWithError(st->dispatch_table,
                                              (PyObject *)type);

The problem is that type is NULL. It tries to get the attribute tp_hash and
it segfaults.

I tried to change the header of the type to:

PyVarObject_HEAD_INIT(&PyType_Type, 0)

This way it works but, as known, it does not compile on Windows.

The strange fact is that pickling the main type works, even if the type is
NULL, as suggested for a custom type. This is the main type:

PyTypeObject PyFrozenDict_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "frozendict." FROZENDICT_CLASS_NAME,        /* tp_name */
    sizeof(PyFrozenDictObject),                 /* tp_basicsize */
    0,                                          /* tp_itemsize */
    (destructor)dict_dealloc,                   /* tp_dealloc */
    0,                                          /* tp_vectorcall_offset */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_as_async */
    (reprfunc)frozendict_repr,                  /* tp_repr */
    &frozendict_as_number,                      /* tp_as_number */
    &dict_as_sequence,                          /* tp_as_sequence */
    &frozendict_as_mapping,                     /* tp_as_mapping */
    (hashfunc)frozendict_hash,                  /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
        | Py_TPFLAGS_BASETYPE
        | _Py_TPFLAGS_MATCH_SELF
        | Py_TPFLAGS_MAPPING,                   /* tp_flags */
    frozendict_doc,                             /* tp_doc */
    dict_traverse,                              /* tp_traverse */
    0,                                          /* tp_clear */
    dict_richcompare,                           /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    (getiterfunc)frozendict_iter,               /* tp_iter */
    0,                                          /* tp_iternext */
    frozendict_mapp_methods,                    /* tp_methods */
    0,                                          /* tp_members */
    0,                                          /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    0,                                          /* tp_init */
    PyType_GenericAlloc,                        /* tp_alloc */
    frozendict_new,                             /* tp_new */
    PyObject_GC_Del,                            /* tp_free */
    .tp_vectorcall = frozendict_vectorcall,
};
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to