https://github.com/python/cpython/commit/0bb9ef9695d30c9ca90a8773e40b05ff5073cc17
commit: 0bb9ef9695d30c9ca90a8773e40b05ff5073cc17
branch: main
author: Neil Schemenauer <[email protected]>
committer: nascheme <[email protected]>
date: 2026-11-08T14:37:43-07:00
summary:
Propagate errors from slot updates in type_setattro() (gh-161587)
Handle failures of update_slot(), since it can fail in the
default build due to non-str keys.
files:
M Lib/test/test_descr.py
M Objects/typeobject.c
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index c4c4d0858ec00b..2f5953ba096d43 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4181,6 +4181,28 @@ def test_pow_wrapper_error_messages(self):
'expected 1 or 2 arguments, got 3',
int().__rpow__, 1, 2, 3)
+ def test_setattr_slot_update_error(self):
+ # An error raised while updating the slots of subclasses must be
+ # propagated by the attribute assignment.
+ class K:
+ def __hash__(self):
+ return hash('__repr__')
+ def __eq__(self, other):
+ raise ZeroDivisionError
+
+ class A:
+ pass
+
+ with self.assertWarns(RuntimeWarning):
+ B = type('B', (A,), {K(): 1})
+ if support.Py_GIL_DISABLED:
+ # The slot update skips non-str keys without comparing them.
+ A.__repr__ = lambda self: 'A'
+ else:
+ with self.assertRaises(ZeroDivisionError):
+ A.__repr__ = lambda self: 'A'
+ self.assertEqual(repr(A()), 'A')
+
def test_mutable_bases(self):
# Testing mutable bases...
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 9833c338679d33..ee8c2090e6397d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -6671,11 +6671,11 @@ type_update_dict(PyTypeObject *type, PyDictObject
*dict, PyObject *name,
return 0;
}
-static void
+static int
update_slot_after_setattr(PyTypeObject *type, PyObject *name)
{
types_stop_world();
- update_slot(type, name);
+ int res = update_slot(type, name);
types_start_world();
#ifdef Py_GIL_DISABLED
// Invalidate again, after the slots are updated and while TYPE_LOCK is
@@ -6686,6 +6686,7 @@ update_slot_after_setattr(PyTypeObject *type, PyObject
*name)
ASSERT_TYPE_LOCK_HELD();
_PyType_Modified_Unlocked(type);
#endif
+ return res;
}
static int
@@ -6774,7 +6775,7 @@ type_setattro(PyObject *self, PyObject *name, PyObject
*value)
if (res == 0) {
if (is_dunder_name(name) && has_slotdef(name)) {
// The name corresponds to a type slot.
- update_slot_after_setattr(type, name);
+ res = update_slot_after_setattr(type, name);
}
}
END_TYPE_DICT_LOCK();
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]