summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeroen Demeyer <J.Demeyer@UGent.be>2019-09-10 11:21:57 (GMT)
committerT. Wouters <thomas@python.org>2019-09-10 11:21:57 (GMT)
commit57ea33560662e0f20a3b0334bb20065771edf4da (patch)
tree5a8e4a23ec325a2a8ba6c121a123cd97339cbf06
parentf958377b67c36a98d4df67b94c01eb29e3104f61 (diff)
downloadcpython-57ea33560662e0f20a3b0334bb20065771edf4da.zip
cpython-57ea33560662e0f20a3b0334bb20065771edf4da.tar.gz
cpython-57ea33560662e0f20a3b0334bb20065771edf4da.tar.bz2
bpo-37619: update_one_slot() should not ignore wrapper descriptors for wrong type (GH-14836)
-rw-r--r--Lib/test/test_descr.py12
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-07-18-11-50-49.bpo-37619.X6Lulo.rst3
-rw-r--r--Objects/typeobject.c19
3 files changed, 28 insertions, 6 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 4368bb5..796e60a 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 0000000..8723d3d
--- /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 71d7f6f0..883bc22 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -7307,14 +7307,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 &&