Closed DinoV closed 2 weeks ago
Some questions comments below. Biggest questions is that now that we are accessing the
dict
directly instead of through_PyObject_GenericSetAttrWithDict
, how do we know that the other cases handled by_PyObject_GenericSetAttrWithDict
are not necessary in_Py_type_getattro
?
This is part of the reason why I assert:
assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_INLINE_VALUES));
assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_MANAGED_DICT));
In type_setattro. Type objects will always have a dictptr, so we'll either go to _PyObjectDict_SetItem
if the dict doesn't exist yet or do the get/set if they do. _PyObjectDict_SetItem
is just going to do a get/set as well. And because types don't have a managed dict they don't have shared keys.
Also, I think this merits a NEWS entry.
Also, I think this merits a NEWS entry. I opened #118492 to track the issue that is fixed when the GIL is present and blurb'd it.
Hi! The buildbot iOS ARM64 Simulator 3.x has failed when building commit 5a1618a2c8c108b8c73aa9459b63f0dbd66b60f6.
What do you need to do:
You can take a look at the buildbot page here:
https://buildbot.python.org/all/#builders/1380/builds/238
Failed tests:
Failed subtests:
Summary of the results of the build (if available):
==
Lookups from the type cache can be exposed to some races. One of those is that
_PyType_Lookup
isn't increfing the result, so the resulting value can become invalid at any point. This adds a new_PyType_Fetch
API which does the incref. Most places are updated to use the new API except for the specializer which isn't safe in free-threaded builds yet.But there are also issues around when we do a store into the dict and signal that the type is modified. A race can occur where the old value is removed from the dict and before we invalidate the type version. This can be seen today w/ the GIL when the value in the dict has a finalizer - accessing the type cache and the type's mapping proxy return inconsistent results.
This fixes these issues by making the update to the dict and the type modified update an atomic operation. We also capture the previous value in the dictionary and don't free it until after we've made the atomic update. This basically inlines a much simplified version of
_PyObject_GenericSetAttrWithDict
intotype_setattro
which can lock mutation against types as well as against the type's dict.When updating we first clear the type version so concurrent reads of the type cache won't hit. We then replace the existing value and finish the type modified process.