gh-118362: Fix thread safety around lookups from the type cache in the face of concurrent mutators (#118454)

Add _PyType_LookupRef and use incref before setting attribute on type
Makes setting an attribute on a class and signaling type modified atomic
Avoid adding re-entrancy exposing the type cache in an inconsistent state by decrefing after type is updated
This commit is contained in:
Dino Viehland 2024-05-06 10:50:35 -07:00 committed by GitHub
parent e6b213ee3f
commit 5a1618a2c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 439 additions and 126 deletions

View file

@ -2511,9 +2511,9 @@ _collections__count_elements_impl(PyObject *module, PyObject *mapping,
/* Only take the fast path when get() and __setitem__()
* have not been overridden.
*/
mapping_get = _PyType_Lookup(Py_TYPE(mapping), &_Py_ID(get));
mapping_get = _PyType_LookupRef(Py_TYPE(mapping), &_Py_ID(get));
dict_get = _PyType_Lookup(&PyDict_Type, &_Py_ID(get));
mapping_setitem = _PyType_Lookup(Py_TYPE(mapping), &_Py_ID(__setitem__));
mapping_setitem = _PyType_LookupRef(Py_TYPE(mapping), &_Py_ID(__setitem__));
dict_setitem = _PyType_Lookup(&PyDict_Type, &_Py_ID(__setitem__));
if (mapping_get != NULL && mapping_get == dict_get &&
@ -2587,6 +2587,8 @@ _collections__count_elements_impl(PyObject *module, PyObject *mapping,
}
done:
Py_XDECREF(mapping_get);
Py_XDECREF(mapping_setitem);
Py_DECREF(it);
Py_XDECREF(key);
Py_XDECREF(newval);

View file

@ -1096,7 +1096,7 @@ static int
UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
/* XXX Should we disallow deleting _fields_? */
if (-1 == PyObject_GenericSetAttr(self, key, value))
if (-1 == PyType_Type.tp_setattro(self, key, value))
return -1;
if (PyUnicode_Check(key) &&

View file

@ -177,8 +177,7 @@ normalizeUserObj(PyObject *obj)
PyObject *modname = fn->m_module;
if (name != NULL) {
PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
Py_XINCREF(mo);
PyObject *mo = _PyType_LookupRef(Py_TYPE(self), name);
Py_DECREF(name);
if (mo != NULL) {
PyObject *res = PyObject_Repr(mo);

View file

@ -99,10 +99,11 @@ slot_tp_del(PyObject *self)
return;
}
/* Execute __del__ method, if any. */
del = _PyType_Lookup(Py_TYPE(self), tp_del);
del = _PyType_LookupRef(Py_TYPE(self), tp_del);
Py_DECREF(tp_del);
if (del != NULL) {
res = PyObject_CallOneArg(del, self);
Py_DECREF(del);
if (res == NULL)
PyErr_WriteUnraisable(del);
else