bpo-37619: update_one_slot() should not ignore wrapper descriptors for wrong type (GH-14836)

This commit is contained in:
Jeroen Demeyer 2019-09-10 13:21:57 +02:00 committed by T. Wouters
parent f958377b67
commit 57ea335606
3 changed files with 28 additions and 6 deletions

View File

@ -4649,6 +4649,18 @@ order (MRO) for bases """
self.assertEqual(x["y"], 42) self.assertEqual(x["y"], 42)
self.assertEqual(x, -x) self.assertEqual(x, -x)
def test_wrong_class_slot_wrapper(self):
# Check bpo-37619: a wrapper descriptor taken from the wrong class
# should raise an exception instead of silently being ignored
class A(int):
__eq__ = str.__eq__
__add__ = str.__add__
a = A()
with self.assertRaises(TypeError):
a == a
with self.assertRaises(TypeError):
a + a
def test_slot_shadows_class_variable(self): def test_slot_shadows_class_variable(self):
with self.assertRaises(ValueError) as cm: with self.assertRaises(ValueError) as cm:
class X: class X:

View File

@ -0,0 +1,3 @@
When adding a wrapper descriptor from one class to a different class
(for example, setting ``__add__ = str.__add__`` on an ``int`` subclass),
an exception is correctly raised when the operator is called.

View File

@ -7307,13 +7307,20 @@ update_one_slot(PyTypeObject *type, slotdef *p)
if (tptr == NULL || tptr == ptr) if (tptr == NULL || tptr == ptr)
generic = p->function; generic = p->function;
d = (PyWrapperDescrObject *)descr; d = (PyWrapperDescrObject *)descr;
if (d->d_base->wrapper == p->wrapper && if ((specific == NULL || specific == d->d_wrapped) &&
d->d_base->wrapper == p->wrapper &&
PyType_IsSubtype(type, PyDescr_TYPE(d))) PyType_IsSubtype(type, PyDescr_TYPE(d)))
{ {
if (specific == NULL ||
specific == d->d_wrapped)
specific = d->d_wrapped; specific = d->d_wrapped;
else }
else {
/* We cannot use the specific slot function because either
- it is not unique: there are multiple methods for this
slot and they conflict
- the signature is wrong (as checked by the ->wrapper
comparison above)
- it's wrapping the wrong class
*/
use_generic = 1; use_generic = 1;
} }
} }