Where does PyType_Type.tp_alloc get first initialized?

Looking through the code in typeobject.c, and looks like PyType_Type.tp_alloc is first statically set to zero on line 3592:

    type_new,                                   /* tp_new */

But, in type_new, the tp_alloc function is called for all new type instances, on line typeobject.c:2585:

    /* Allocate the type object */
    type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots);
    if (type == NULL)
        goto error;

It looks like metatype is PyType_Type if no metatype is specified.

Is there some code that’s called before type_new is ever called to initialize the PyType_Type structure?

I’m guessing something sets PyType_Type.tp_alloc to PyType_GenericAlloc, but can’t seem to figure out where.

1 Like

Since PyType_Type's tp_alloc is set to NULL, it’s inherited from its base class, PyBaseObject_Type (i.e. object), whose tp_alloc is set to PyType_GenericAlloc.

The inherit_slots function does the inheritance – in simple cases like tp_alloc, the pointer is copied from the base class.

And inherit_slots is called from PyType_Ready, which is (for the core built-in types) called from _PyTypes_Init.


FWIW, if you use a debugger, you can explore things like this by setting watchpoints, which stop your program when a given value changes.
Here’s how to do it in GDB:

(gdb) watch PyType_Type.tp_alloc
Hardware watchpoint 1: PyType_Type.tp_alloc

(gdb) run
Starting program: /home/pviktori/dev/cpython/python 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.30-10.fc31.x86_64
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Hardware watchpoint 1: PyType_Type.tp_alloc

Old value = (allocfunc) 0x0
New value = (allocfunc) 0x481746 <PyType_GenericAlloc>
0x000000000047b34d in inherit_slots (type=type@entry=0x7485a0 <PyType_Type>, 
    base=0x7482a0 <PyBaseObject_Type>) at Objects/typeobject.c:5243
5243	        COPYSLOT(tp_alloc);

(gdb) backtrace
#0  0x000000000047b34d in inherit_slots (type=type@entry=0x7485a0 <PyType_Type>, 
    base=0x7482a0 <PyBaseObject_Type>) at Objects/typeobject.c:5243
#1  0x0000000000481d6e in PyType_Ready (type=0x7485a0 <PyType_Type>) at Objects/typeobject.c:5395
#2  0x000000000046480e in _PyTypes_Init () at Objects/object.c:1738
#3  0x0000000000514f9f in pycore_init_types (tstate=tstate@entry=0x78f6b0) at Python/pylifecycle.c:576
#4  0x0000000000516597 in pycore_interp_init (tstate=0x78f6b0) at Python/pylifecycle.c:713
#5  0x0000000000516722 in pyinit_config (runtime=runtime@entry=0x786e00 <_PyRuntime>, 
    tstate_p=tstate_p@entry=0x7fffffffd748, config=config@entry=0x7fffffffd590)
    at Python/pylifecycle.c:756
#6  0x0000000000517d61 in pyinit_core (runtime=runtime@entry=0x786e00 <_PyRuntime>, 
    src_config=src_config@entry=0x7fffffffd7b0, tstate_p=tstate_p@entry=0x7fffffffd748)
    at Python/pylifecycle.c:917
#7  0x0000000000518798 in Py_InitializeFromConfig (config=config@entry=0x7fffffffd7b0)
    at Python/pylifecycle.c:1127
#8  0x000000000041da99 in pymain_init (args=args@entry=0x7fffffffd990) at Modules/main.c:66
#9  0x000000000041eaba in pymain_main (args=args@entry=0x7fffffffd990) at Modules/main.c:653
#10 0x000000000041eb47 in Py_BytesMain (argc=<optimized out>, argv=<optimized out>) at Modules/main.c:686
#11 0x000000000041d6df in main (argc=<optimized out>, argv=<optimized out>) at ./Programs/python.c:16
2 Likes