From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Sep 2019 12:55:12 +0000 (-0700) Subject: bpo-37619: update_one_slot() should not ignore wrapper descriptors for wrong type... X-Git-Tag: v3.8.0rc1~232 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eb1bc48c74f4f8af88b5276729f9652201e46324;p=python bpo-37619: update_one_slot() should not ignore wrapper descriptors for wrong type (GH-15838) (cherry picked from commit 57ea33560662e0f20a3b0334bb20065771edf4da) Co-authored-by: Jeroen Demeyer --- diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 741cb6dce2..c4d900a8c1 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4649,6 +4649,18 @@ order (MRO) for bases """ self.assertEqual(x["y"], 42) 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): with self.assertRaises(ValueError) as cm: class X: diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-07-18-11-50-49.bpo-37619.X6Lulo.rst b/Misc/NEWS.d/next/Core and Builtins/2019-07-18-11-50-49.bpo-37619.X6Lulo.rst new file mode 100644 index 0000000000..8723d3d9e9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-07-18-11-50-49.bpo-37619.X6Lulo.rst @@ -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. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8ece218275..f42caedf6c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7243,14 +7243,21 @@ update_one_slot(PyTypeObject *type, slotdef *p) if (tptr == NULL || tptr == ptr) generic = p->function; 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))) { - if (specific == NULL || - specific == d->d_wrapped) - specific = d->d_wrapped; - else - use_generic = 1; + specific = d->d_wrapped; + } + 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; } } else if (Py_TYPE(descr) == &PyCFunction_Type &&