When does `PyType_Type.tp_alloc get assigned to PyType_GenericAlloc ?

Hi everyone, I've a question about the implementation of the `type` builtin (in Python 3.5). In Objects/typeobject.c, the `tp_alloc` slot of PyType_Type gets set to 0. However, I can see (using gdb) that it later gets assigned to `&PyType_GenericAlloc`. I'd argue that this makes sense because, in `type_new`, there is a line where that member function gets called without previously checking whether that member points to something: ``` /* Allocate the type object */ type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots); ``` Yet, I can't seem to understand where and when does the `tp_alloc` slot of PyType_Type get re-assigned to PyType_GenericAlloc. Does that even happen? Or am I missing something bigger? And, just out of further curiosity, why doesn't the aforementioned slot get initialised to `PyType_GenericAlloc` in the first place? Thanks a lot.

I think it's probably line 2649 in typeobject.c, in type_new(): type->tp_alloc = PyType_GenericAlloc; On Sun, Feb 7, 2016 at 5:58 AM, Randy Eels <randyeels@gmail.com> wrote:
Hi everyone,
I've a question about the implementation of the `type` builtin (in Python 3.5).
In Objects/typeobject.c, the `tp_alloc` slot of PyType_Type gets set to 0. However, I can see (using gdb) that it later gets assigned to `&PyType_GenericAlloc`. I'd argue that this makes sense because, in `type_new`, there is a line where that member function gets called without previously checking whether that member points to something:
``` /* Allocate the type object */ type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots); ```
Yet, I can't seem to understand where and when does the `tp_alloc` slot of PyType_Type get re-assigned to PyType_GenericAlloc. Does that even happen? Or am I missing something bigger?
And, just out of further curiosity, why doesn't the aforementioned slot get initialised to `PyType_GenericAlloc` in the first place?
Thanks a lot.
_______________________________________________ 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/guido%40python.org
-- --Guido van Rossum (python.org/~guido)

On Sun, Feb 7, 2016 at 7:58 AM, Randy Eels <randyeels@gmail.com> wrote:
Yet, I can't seem to understand where and when does the `tp_alloc` slot of PyType_Type get re-assigned to PyType_GenericAlloc. Does that even happen? Or am I missing something bigger?
_Py_InitializeEx_Private in Python/pylifecycle.c calls _Py_ReadyTypes in Objects/object.c. This calls PyType_Ready(&PyType_Type) in Objects/typeobject.c, which assigns type->tp_base = &PyBaseObject_Type and then calls inherit_slots. This executes COPYSLOT(tp_alloc), which assigns PyType_Type.tp_alloc = PyBaseObject_Type.tp_alloc, which is statically assigned as PyType_GenericAlloc. Debug trace on Windows: 0:000> bp python35!PyType_Ready 0:000> g Breakpoint 0 hit python35!PyType_Ready: 00000000`6502d160 4053 push rbx 0:000> ?? ((PyTypeObject *)@rcx)->tp_name char * 0x00000000`650e4044 "object" 0:000> g Breakpoint 0 hit python35!PyType_Ready: 00000000`6502d160 4053 push rbx 0:000> ?? ((PyTypeObject *)@rcx)->tp_name char * 0x00000000`651d8e5c "type" 0:000> bp python35!inherit_slots 0:000> g Breakpoint 1 hit python35!inherit_slots: 00000000`6502c440 48895c2408 mov qword ptr [rsp+8],rbx ss:00000000`0028f960={ python35!PyType_Type (00000000`6527cba0)} At entry to inherit_slots, PyType_Type.tp_alloc is NULL: 0:000> ?? python35!PyType_Type.tp_alloc <function> * 0x00000000`00000000 0:000> pt python35!inherit_slots+0xd17: 00000000`6502d157 c3 ret At exit it's set to PyType_GenericAlloc: 0:000> ?? python35!PyType_Type.tp_alloc <function> * 0x00000000`65025580 0:000> ln 65025580 (00000000`65025580) python35!PyType_GenericAlloc | (00000000`650256a0) python35!PyType_GenericNew Exact matches: python35!PyType_GenericAlloc (void)

On Sun, Feb 7, 2016 at 8:45 PM, Guido van Rossum <guido@python.org> wrote:
I think it's probably line 2649 in typeobject.c, in type_new():
type->tp_alloc = PyType_GenericAlloc;
I pondered it but it doesn't seem to be that. Isn't `type_new` called *after* PyType_Type.tp_alloc has been called? I thought that line was only being executed for user-defined types, and maybe some built-in types, but certainly not PyType_Type. On Sun, Feb 7, 2016 at 9:27 PM, eryk sun <eryksun@gmail.com> wrote:
On Sun, Feb 7, 2016 at 7:58 AM, Randy Eels <randyeels@gmail.com> wrote:
Yet, I can't seem to understand where and when does the `tp_alloc` slot
of
PyType_Type get re-assigned to PyType_GenericAlloc. Does that even happen? Or am I missing something bigger?
_Py_InitializeEx_Private in Python/pylifecycle.c calls _Py_ReadyTypes in Objects/object.c. This calls PyType_Ready(&PyType_Type) in Objects/typeobject.c, which assigns type->tp_base = &PyBaseObject_Type and then calls inherit_slots. This executes COPYSLOT(tp_alloc), which assigns PyType_Type.tp_alloc = PyBaseObject_Type.tp_alloc, which is statically assigned as PyType_GenericAlloc.
Debug trace on Windows:
0:000> bp python35!PyType_Ready 0:000> g Breakpoint 0 hit python35!PyType_Ready: 00000000`6502d160 4053 push rbx 0:000> ?? ((PyTypeObject *)@rcx)->tp_name char * 0x00000000`650e4044 "object" 0:000> g Breakpoint 0 hit python35!PyType_Ready: 00000000`6502d160 4053 push rbx 0:000> ?? ((PyTypeObject *)@rcx)->tp_name char * 0x00000000`651d8e5c "type" 0:000> bp python35!inherit_slots 0:000> g Breakpoint 1 hit python35!inherit_slots: 00000000`6502c440 48895c2408 mov qword ptr [rsp+8],rbx ss:00000000`0028f960={ python35!PyType_Type (00000000`6527cba0)}
At entry to inherit_slots, PyType_Type.tp_alloc is NULL:
0:000> ?? python35!PyType_Type.tp_alloc <function> * 0x00000000`00000000 0:000> pt python35!inherit_slots+0xd17: 00000000`6502d157 c3 ret
At exit it's set to PyType_GenericAlloc:
0:000> ?? python35!PyType_Type.tp_alloc <function> * 0x00000000`65025580 0:000> ln 65025580 (00000000`65025580) python35!PyType_GenericAlloc | (00000000`650256a0) python35!PyType_GenericNew Exact matches: python35!PyType_GenericAlloc (void)
This makes quite a bit of sense. I completely overlooked the interpreter init routines. Thank you both Guido and eryk!
participants (3)
-
eryk sun
-
Guido van Rossum
-
Randy Eels