return _Py_type_getattro_impl((PyTypeObject *)type, name, NULL);
}
+static int
+type_update_dict(PyTypeObject *type, PyDictObject *dict, PyObject *name,
+ PyObject *value, PyObject **old_value)
+{
+ // We don't want any re-entrancy between when we update the dict
+ // and call type_modified_unlocked, including running the destructor
+ // of the current value as it can observe the cache in an inconsistent
+ // state. Because we have an exact unicode and our dict has exact
+ // unicodes we know that this will all complete without releasing
+ // the locks.
+ if (_PyDict_GetItemRef_Unicode_LockHeld(dict, name, old_value) < 0) {
+ return -1;
+ }
+
+ /* Clear the VALID_VERSION flag of 'type' and all its
+ subclasses. This could possibly be unified with the
+ update_subclasses() recursion in update_slot(), but carefully:
+ they each have their own conditions on which to stop
+ recursing into subclasses. */
+ type_modified_unlocked(type);
+
+ if (_PyDict_SetItem_LockHeld(dict, name, value) < 0) {
+ PyErr_Format(PyExc_AttributeError,
+ "type object '%.50s' has no attribute '%U'",
+ ((PyTypeObject*)type)->tp_name, name);
+ _PyObject_SetAttributeErrorContext((PyObject *)type, name);
+ return -1;
+ }
+
+ if (is_dunder_name(name)) {
+ return update_slot(type, name);
+ }
+
+ return 0;
+}
+
static int
type_setattro(PyObject *self, PyObject *name, PyObject *value)
{
assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_INLINE_VALUES));
assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_MANAGED_DICT));
- PyObject *old_value;
+ PyObject *old_value = NULL;
PyObject *descr = _PyType_LookupRef(metatype, name);
if (descr != NULL) {
descrsetfunc f = Py_TYPE(descr)->tp_descr_set;
if (f != NULL) {
- old_value = NULL;
res = f(descr, (PyObject *)type, value);
goto done;
}
}
END_TYPE_LOCK();
if (dict == NULL) {
- return -1;
+ res = -1;
+ goto done;
}
}
- // We don't want any re-entrancy between when we update the dict
- // and call type_modified_unlocked, including running the destructor
- // of the current value as it can observe the cache in an inconsistent
- // state. Because we have an exact unicode and our dict has exact
- // unicodes we know that this will all complete without releasing
- // the locks.
BEGIN_TYPE_DICT_LOCK(dict);
-
- if (_PyDict_GetItemRef_Unicode_LockHeld((PyDictObject *)dict, name, &old_value) < 0) {
- return -1;
- }
-
- /* Clear the VALID_VERSION flag of 'type' and all its
- subclasses. This could possibly be unified with the
- update_subclasses() recursion in update_slot(), but carefully:
- they each have their own conditions on which to stop
- recursing into subclasses. */
- type_modified_unlocked(type);
-
- res = _PyDict_SetItem_LockHeld((PyDictObject *)dict, name, value);
-
- if (res == 0) {
- if (is_dunder_name(name)) {
- res = update_slot(type, name);
- }
- }
- else if (PyErr_ExceptionMatches(PyExc_KeyError)) {
- PyErr_Format(PyExc_AttributeError,
- "type object '%.50s' has no attribute '%U'",
- ((PyTypeObject*)type)->tp_name, name);
-
- _PyObject_SetAttributeErrorContext((PyObject *)type, name);
- }
-
+ res = type_update_dict(type, (PyDictObject *)dict, name, value, &old_value);
assert(_PyType_CheckConsistency(type));
-
END_TYPE_DICT_LOCK();
+
done:
Py_DECREF(name);
Py_XDECREF(descr);