From 9bc9512271e5e2645cff30e397ed35d6aa8d7fad Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 11 Jan 2023 21:42:23 +0300 Subject: [PATCH 1/3] gh-100942: Fix crash on `property` subtypes with weird `__new__` --- Lib/test/test_property.py | 10 ++++++++++ .../2023-01-11-21-41-58.gh-issue-100942._jnwot.rst | 1 + Objects/descrobject.c | 5 +++++ 3 files changed, 16 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-11-21-41-58.gh-issue-100942._jnwot.rst diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index d07b8632aa8722..1f1df91960893c 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -403,6 +403,16 @@ def spam(self): return 2 self.assertEqual(Foo.spam.__doc__, "a new docstring") + def test_gh100942(self): + # See https://github.com/python/cpython/issues/100942 + class pro(property): + def __new__(typ, *args, **kwargs): + return "abcdef" + + p = property.__new__(pro) + with self.assertRaises(TypeError): + p.getter(lambda self: 1) # this line was causing a crash + class _PropertyUnreachableAttribute: msg_format = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-11-21-41-58.gh-issue-100942._jnwot.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-11-21-41-58.gh-issue-100942._jnwot.rst new file mode 100644 index 00000000000000..8fe47d0dd97bab --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-11-21-41-58.gh-issue-100942._jnwot.rst @@ -0,0 +1 @@ +Fix crash on ``property`` subclasses with weird ``__new__`` methods. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index c545b90c6283e1..82e2d82e7def71 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1711,6 +1711,11 @@ property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del) Py_DECREF(type); if (new == NULL) return NULL; + if (!PyObject_TypeCheck(new, &PyProperty_Type)) { + PyErr_Format(PyExc_TypeError, "property instance expected, got %.50s", + Py_TYPE(new)->tp_name); + return NULL; + } Py_XSETREF(((propertyobject *) new)->prop_name, Py_XNewRef(pold->prop_name)); return new; From a2babb4f5837bc089c54dcb6c7162a53e88be7cf Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 11 Jan 2023 21:44:19 +0300 Subject: [PATCH 2/3] Also test `setter` and `deleter` --- Lib/test/test_property.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index 1f1df91960893c..77b6e594e907cb 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -412,6 +412,10 @@ def __new__(typ, *args, **kwargs): p = property.__new__(pro) with self.assertRaises(TypeError): p.getter(lambda self: 1) # this line was causing a crash + with self.assertRaises(TypeError): + p.setter(lambda self, val: 1) # this line was causing a crash + with self.assertRaises(TypeError): + p.deleter(lambda self: 1) # this line was causing a crash class _PropertyUnreachableAttribute: From 365556cddc802163fe96fc5ffacdbd6992960dde Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 12 Jan 2023 01:11:56 +0300 Subject: [PATCH 3/3] Alternative approach: do not raise, just ignore the cast --- Lib/test/test_property.py | 11 +++++------ Objects/descrobject.c | 8 +++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index 77b6e594e907cb..05faaba842e22e 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -410,12 +410,11 @@ def __new__(typ, *args, **kwargs): return "abcdef" p = property.__new__(pro) - with self.assertRaises(TypeError): - p.getter(lambda self: 1) # this line was causing a crash - with self.assertRaises(TypeError): - p.setter(lambda self, val: 1) # this line was causing a crash - with self.assertRaises(TypeError): - p.deleter(lambda self: 1) # this line was causing a crash + + # These lines were causing crashes: + p.getter(lambda self: 1) + p.setter(lambda self, val: 1) + p.deleter(lambda self: 1) class _PropertyUnreachableAttribute: diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 82e2d82e7def71..41c113ae130179 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1711,13 +1711,11 @@ property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del) Py_DECREF(type); if (new == NULL) return NULL; - if (!PyObject_TypeCheck(new, &PyProperty_Type)) { - PyErr_Format(PyExc_TypeError, "property instance expected, got %.50s", - Py_TYPE(new)->tp_name); - return NULL; + if (PyObject_TypeCheck(new, &PyProperty_Type)) { + Py_XSETREF(((propertyobject *) new)->prop_name, + Py_XNewRef(pold->prop_name)); } - Py_XSETREF(((propertyobject *) new)->prop_name, Py_XNewRef(pold->prop_name)); return new; }