PEP-384 talks about defining a Stable ABI by making PyTypeObject opaque. Thus, 
banning the use of static PyTypeObjects.

Specifically, I’d like to focus on those static PyTypeObjects that are 
initialized as StructSequences. As of today, there are 14 instances of these 
types (in timemodule.c, posixmodule.c, etc.) within cpython/Modules. These are 
all initialized through PyStructSequence_InitType2. This is very problematic 
when trying to make these types conform to PEP-384 as they are used through 
static PyTypeObjects.

Problems:

  *   PyStructSequence_InitType2 overrides the PyTypeObject:

This C-API does a direct memcpy from a “prototype” structure. This effectively 
overrides anything set within the PyTypeObject. For example, if we were to 
initialize a heap allocated PyTypeObject and pass it on to this function, the 
C-API would just get rid of the Py_TPFLAG_HEAPTYPE flag, causing issues with 
the GC.


  *   PyStructSequence_InitType2 does not work with heap allocated 
PyTypeObjects:

Even if the function is fixed to preserve the state of the PyTypeObject and 
only overriding the specific slots (i.e. tp_new, tp_repr, etc.), it is expected 
that PyStructSequence_InitType2 will call PyType_Ready on the object. That 
means that the incoming object shouldn’t be initialized by a function such as 
PyType_FromSpec, as that would have already called PyType_Ready on it. 
Therefore, PyStructSequence_InitType2 will now have the responsibility of 
setting all the slots and properties of the PyHeapTypeObject, which is not 
feasible.


  *   PyStructSequence_NewType is non-functional:

This function was meant to be used as a way of creating a heap-allocated 
PyTypeObject that be passed to PyStructSequence_InitType2, effectively 
returning a heap allocated PyTypeObject. The current implementation doesn’t 
work in practice. Given that this struct is created in the heap, the GC has 
control over it. Thus, when the GC tries to traverse the type it complains 
with: “Error: type_traverse() called for non-heap type”, since it doesn’t have 
the Py_TPFLAG_HEAPTYPE flag. If we add the flag, we run into bullet point 1, if 
we are able to preserve the flag then we will still run into the problem of 
bullet point 2. Extra note: This C-API is not being used anywhere within 
CPython itself.

Solution:

  *   Fix the implementation of PyStructSequence_NewType:

The best solution would be to fix the implementation of this function. This can 
easily be done by dynamically creating a PyType_Spec and calling PyType_FromSpec

```

PyObject*

PyStructSequence_NewType(PyStructSequence_Desc *desc)

{

    // …

    PyType_Spec* spec = PyMem_NEW(PyType_Spec, 1);

    spec->name = desc->name;

    spec->basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);

    spec->itemsize = sizeof(PyObject *);

    spec->flags = Py_TPFLAGS_DEFAULT;

    spec->slots = PyMem_NEW(PyType_Slot, 6);

    spec->slots[0].slot = Py_tp_dealloc;

    spec->slots[0].pfunc = (destructor)structseq_dealloc;

    // …

    bases = PyTuple_Pack(1, &PyTuple_Type);

   type = PyType_FromSpecWithBases(spec, bases);

    // …

```



This will cleanly create a heap allocated PyStructSequence which can be used 
just like any stack allocated PyTypeObject initialized through 
PyStructSequence_InitType2. This means that any C-Extension should be using 
PyStructSequence_NewType and only built-in types should be calling 
PyStructSequence_InitType2. This will enable these types to comply with PEP-384


As an extra, I already have patches for this proposal. They can be found here:

Branch: https://github.com/eduardo-elizondo/cpython/tree/heap-structseq
Reimplement PyStructSequence_NewType:  
https://github.com/eduardo-elizondo/cpython/commit/413f8ca5bc008d84b3397ca1c9565c604d54b661
Patch timemodule with NewType: 
https://github.com/eduardo-elizondo/cpython/commit/0a35ea263a531cb03c06be9efc9e96d68162b308

Thoughts?

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to