Skip to content

Commit 57ea335

Browse files
jdemeyerYhg1s
authored andcommitted
bpo-37619: update_one_slot() should not ignore wrapper descriptors for wrong type (GH-14836)
1 parent f958377 commit 57ea335

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

Lib/test/test_descr.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4649,6 +4649,18 @@ class X(dict):
46494649
self.assertEqual(x["y"], 42)
46504650
self.assertEqual(x, -x)
46514651

4652+
def test_wrong_class_slot_wrapper(self):
4653+
# Check bpo-37619: a wrapper descriptor taken from the wrong class
4654+
# should raise an exception instead of silently being ignored
4655+
class A(int):
4656+
__eq__ = str.__eq__
4657+
__add__ = str.__add__
4658+
a = A()
4659+
with self.assertRaises(TypeError):
4660+
a == a
4661+
with self.assertRaises(TypeError):
4662+
a + a
4663+
46524664
def test_slot_shadows_class_variable(self):
46534665
with self.assertRaises(ValueError) as cm:
46544666
class X:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When adding a wrapper descriptor from one class to a different class
2+
(for example, setting ``__add__ = str.__add__`` on an ``int`` subclass),
3+
an exception is correctly raised when the operator is called.

Objects/typeobject.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7307,14 +7307,21 @@ update_one_slot(PyTypeObject *type, slotdef *p)
73077307
if (tptr == NULL || tptr == ptr)
73087308
generic = p->function;
73097309
d = (PyWrapperDescrObject *)descr;
7310-
if (d->d_base->wrapper == p->wrapper &&
7310+
if ((specific == NULL || specific == d->d_wrapped) &&
7311+
d->d_base->wrapper == p->wrapper &&
73117312
PyType_IsSubtype(type, PyDescr_TYPE(d)))
73127313
{
7313-
if (specific == NULL ||
7314-
specific == d->d_wrapped)
7315-
specific = d->d_wrapped;
7316-
else
7317-
use_generic = 1;
7314+
specific = d->d_wrapped;
7315+
}
7316+
else {
7317+
/* We cannot use the specific slot function because either
7318+
- it is not unique: there are multiple methods for this
7319+
slot and they conflict
7320+
- the signature is wrong (as checked by the ->wrapper
7321+
comparison above)
7322+
- it's wrapping the wrong class
7323+
*/
7324+
use_generic = 1;
73187325
}
73197326
}
73207327
else if (Py_TYPE(descr) == &PyCFunction_Type &&

0 commit comments

Comments
 (0)