Repository navigation
Closed
Labels
3.10 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
Description
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = None
closed_at = <Date 2021-09-21.22:08:50.540>
created_at = <Date 2021-04-07.21:48:22.168>
labels = ['interpreter-core', '3.10']
title = 'Rework C types initialization'
updated_at = <Date 2021-09-21.22:08:50.540>
user = 'https://github.com/vstinner'bugs.python.org fields:
activity = <Date 2021-09-21.22:08:50.540>
actor = 'vstinner'
assignee = 'none'
closed = True
closed_date = <Date 2021-09-21.22:08:50.540>
closer = 'vstinner'
components = ['Interpreter Core']
creation = <Date 2021-04-07.21:48:22.168>
creator = 'vstinner'
dependencies = []
files = []
hgrepos = []
issue_num = 43770
keywords = ['patch']
message_count = 14.0
messages = ['390484', '390490', '390493', '390506', '390510', '390519', '390742', '390799', '390955', '390962', '390964', '396420', '396807', '402383']
nosy_count = 2.0
nosy_names = ['vstinner', 'corona10']
pr_nums = ['25263', '25265', '25266', '25275', '25325', '25336', '25373', '25388', '26879', '26880', '26881', '26946']
priority = 'normal'
resolution = 'fixed'
stage = 'resolved'
status = 'closed'
superseder = None
type = None
url = 'https://bugs.python.org/issue43770'
versions = ['Python 3.10']Metadata
Metadata
Assignees
Labels
3.10 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
Activity
vstinner commentedon Apr 7, 2021
Currently, PyType_Ready() is called late on many static types, which can lead to bugs. For example, PyObject_SetAttr() can fail if the type of the object is not ready yet. PyType_Read() is responsible to initialize tp_getattro and tp_setattro members of the PyTypeObject structure.
We must explicitly initialize all static types before using them.
Moreover, many static types initialize explicitly :
and:
whereas it's the default implementation. They can be omitted.
I created this issue as a placeholder for multiple changes to modify how types implemented in C are initialized.
vstinner commentedon Apr 7, 2021
New changeset a518099 by Victor Stinner in branch 'master':
bpo-43770: Sort types in _PyTypes_Init() (GH-25263)
a518099
vstinner commentedon Apr 7, 2021
New changeset df5dc1c by Victor Stinner in branch 'master':
bpo-43770: _PyTypes_Init() inits more static types (GH-25265)
df5dc1c
vstinner commentedon Apr 8, 2021
New changeset b98eba5 by Victor Stinner in branch 'master':
bpo-43770: _PyTypes_Init() inits _PyAnextAwaitable_Type (GH-25266)
b98eba5
vstinner commentedon Apr 8, 2021
I tried to put assertions in PyObject_GetAttr(), _PyObject_LookupAttr(), _PyObject_GetMethod() and PyObject_SetAttr() to ensure that the type is ready. It breaks many tests, examples:
For example, Modules/_testbuffer.c does not initialize its ndarray type.
Example of crash:
-----------------
Objects/object.c:892: PyObject_GetAttr: Assertion "tp->tp_flags & (1UL << 12)" failed
Enable tracemalloc to get the memory block allocation traceback
object address : 0x7f4d89119a00
object refcount : 4
object type : 0x8768c0
object type name: type
object repr : <class 'ndarray'>
Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: initialized
Current thread 0x00007f4d96eba740 (most recent call first):
File "/home/vstinner/python/master/Lib/test/test_picklebuffer.py", line 80 in test_ndarray_2d
(...)
Extension modules: _testcapi, _testbuffer (total: 2)
-----------------
Another example of crash:
-----------------
Objects/object.c:892: PyObject_GetAttr: Assertion "tp->tp_flags & (1UL << 12)" failed
Enable tracemalloc to get the memory block allocation traceback
object address : 0x7f174ec9aa00
object refcount : 3
object type : 0x8768c0
object type name: type
object repr : <class 'ndarray'>
Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: initialized
Current thread 0x00007f175ca42740 (most recent call first):
File "/home/vstinner/python/master/Lib/test/pickletester.py", line 304 in __reduce_ex__
(...)
Extension modules: _testcapi, _testbuffer, numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg.lapack_lite, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator (total: 16)
-----------------
The C API tries to make the type ready automatically. For example, PyObject_Hash() calls PyType_Ready() if needed and then retry tp_hash:
vstinner commentedon Apr 8, 2021
PR 25275: this is a subtle difference if PyTypeObject.tp_setattro is set statically to PyObject_GenericSetAttr() or if it's inherited by PyType_Ready().
Reference (master)::
With the PR:
Because of that, doctest.DocTestFinder().find(builtins) returns less items, and so test_doctest fails.
vstinner commentedon Apr 10, 2021
New changeset ecf14e6 by Victor Stinner in branch 'master':
bpo-43770: Refactor type_new() function (GH-25325)
ecf14e6
vstinner commentedon Apr 11, 2021
New changeset 53114ff by Victor Stinner in branch 'master':
bpo-43770: Refactor PyType_Ready() function (GH-25336)
53114ff
vstinner commentedon Apr 13, 2021
New changeset 65f058e by Victor Stinner in branch 'master':
bpo-43770: Reorder type_ready() (GH-25373)
65f058e
vstinner commentedon Apr 13, 2021
New changeset a328d73 by Victor Stinner in branch 'master':
bpo-43770: Cleanup type_ready() (GH-25388)
a328d73
vstinner commentedon Apr 13, 2021
If I modify type_ready() to call type_ready_inherit() before type_ready_fill_dict(), some types create a between between their C slot (tp_init) and the Python API in tp_dict (tp_dict["__init__"]).
Example with importlib:
=> FileLoader.tp_init = slot_tp_init
When PyType_Ready() is called on SourceFileLoader, we get:
When inherit_slots() is called, SourceFileLoader.tp_init is set to slot_tp_init().
When add_operators() is called, SourceFileLoader.tp_dict["__init__"] is set to PyDescr_NewWrapper(slot_tp_init).
Problem: we a loop! tp_dict["__init__"] => slot_tp_init => tp_dict["__init__"]
vstinner commentedon Jun 23, 2021
New changeset 2a396d6 by Victor Stinner in branch 'main':
bpo-43770: Cleanup PyModuleDef_Init() (GH-26879)
2a396d6
vstinner commentedon Jul 1, 2021
New changeset dd3adc0 by Victor Stinner in branch 'main':
bpo-43770: Cleanup _PyObject_GetMethod() (GH-26946)
dd3adc0
vstinner commentedon Sep 21, 2021
The code is way more complicated than what I expected. I hope that my work on this issue will help future developers who will try to understand the code. But I prefer to stop the refactoring at this point. I pushed enough changes ;-)