Which field lead to segfault on windows

I tried to create metaclass in c extension:

static PyTypeObject MyMetaClass = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "MyMetaClass",                          // tp_name
    sizeof(MyMetaClassObject),              // tp_basicsize
    0,                                      // tp_itemsize
    (destructor)MyMetaClass_del,            // tp_dealloc
    0,                                      // tp_print
    0,                                      // tp_getattr
    0,                                      // tp_setattr
    0,                                      // tp_reserved
    0,                                      // tp_repr
    0,                                      // tp_as_number
    0,                                      // tp_as_sequence
    0,                                      // tp_as_mapping
    0,                                      // tp_hash
    0,                                      // tp_call
    0,                                      // tp_str
    (getattrofunc)MyMetaClass_getattr,      // tp_getattro
    (setattrofunc)MyMetaClass_setattr,      // tp_setattro
    0,                                      // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                     // tp_flags
    "my metaclass",                         // tp_doc
    0,                                      // tp_traverse
    0,                                      // tp_clear
    0,                                      // tp_richcompare
    0,                                      // tp_weaklistoffset
    0,                                      // tp_iter
    0,                                      // tp_iternext
    0,                                      // tp_methods
    0,                                      // tp_members
    0,                                      // tp_getset
    &PyType_Type,                           // tp_base
    0,                                      // tp_dict
    0,                                      // tp_descr_get
    0,                                      // tp_descr_set
    0,                                      // tp_dictoffset
    0,                                      // tp_init
    0,                                      // tp_alloc
    (newfunc)MyMetaClass_new,               // tp_new
};

And the new function use PyType_type.tp_new to create. The classes created from the function only change tp_getattro, tp_setattro, tp_dealloc. However, the classes can create their instance only on unix. On windows, the creating for the class is successful but when create the instance, it segfault.

More information:
I tried to just first create a class from the metaclass in C too, and it can create its instance on windows.

I believe that Windows is stricter about memory management and will crash immediately when deallocation rules are violated.

It’s hard to say without seeing your deallocator, but my guess is that that’s the culprit.

Are you freeing objects with the type’s tp_free or the original tp_dealloc?

Call tp_free in tp_dealloc.

Another information is that the classes can create their instances in powershell but crash in IDLE shell.

Are they running the same interpreter and module?

Can you print this both in PowerShell and in Idle?

import sys, platform, yourmodule
print("exe:", sys.executable)
print("ver:", sys.version)
print("arch:", platform.architecture())
print("mod:", yourmodule.__file__)

In tp_getattro I use PyEval_GetFrame and PyFrame_GetCode to get the python now code. Is it the reason?

Is there a difference in IDLE running Constructor() vs c = Constructor()?

No. Both caused crash.

Now I tried to just create the class just print something:

#include <Python.h>

typedef struct {
    PyTypeObject typ;
} MyMetaClass;

static PyObject*
MyMetaClass_new(PyTypeObject *type, PyObject *args, PyObject *kwds);

static PyTypeObject MyMetaClassType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "MyMetaClass",             /*tp_name*/
    sizeof(MyMetaClass),       /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    0,                         /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                                      // tp_getattr
    0,                                      // tp_setattr
    0,                                      // tp_reserved
    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*/
    "MyMetaClass objects",                  // tp_doc
    0,                                      // tp_traverse
    0,                                      // tp_clear
    0,                                      // tp_richcompare
    0,                                      // tp_weaklistoffset
    0,                                      // tp_iter
    0,                                      // tp_iternext
    0,                                      // tp_methods
    0,                                      // tp_members
    0,                                      // tp_getset
    &PyType_Type,                           // tp_base
    0,                                      // tp_dict
    0,                                      // tp_descr_get
    0,                                      // tp_descr_set
    0,                                      // tp_dictoffset
    0,                                      // tp_init
    0,                                      // tp_alloc
    (newfunc)MyMetaClass_new,              // tp_new
};

static PyObject*
MyMetaClass_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PySys_WriteStdout("MyMetaClass_new\n");
    PyObject* typ = PyType_Type.tp_new(type, args, kwds);
    PySys_WriteStdout("MyMetaClass_new done\n");
    return typ;
}

static PyMethodDef module_methods[] = {
    {NULL}  /* Sentinel */
};

static struct PyModuleDef metaclassmodule = {
    PyModuleDef_HEAD_INIT,
    "metaclass",   /* name */
    "Test module for metaclass", /* module doc */
    -1,       /* size of per-interpreter state */
    module_methods
};

PyMODINIT_FUNC
PyInit_my_metaclass(void)
{
    PyObject* m;
    
    if (PyType_Ready(&MyMetaClassType) < 0)
        return NULL;

    m = PyModule_Create(&metaclassmodule);
    if (m == NULL)
        return NULL;

    Py_INCREF(&MyMetaClassType);
    if (PyModule_AddObject(m, "MyMetaClass", (PyObject *)&MyMetaClassType) < 0) {
        Py_DECREF(&MyMetaClassType);
        Py_DECREF(m);
        return NULL;
    }

    return m;
}

It is simple, just print something in “__new__” function. However, on windows, it still segfault when the class created by this metaclass creates an instance.

Solved by:

typedef struct {
    PyHeapTypeObject base;
} MyMetaClass;