From 64141382ecbad665d5738ff26d15505f3427c724 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Fri, 30 Apr 2021 15:25:43 +0200 Subject: [PATCH] bpo-43908: check_set_special_type_attr() checks Py_TPFLAGS_IMMUTABLETYPE (GH-25743) check_set_special_type_attr() and type_set_annotations() now check for immutable flag (Py_TPFLAGS_IMMUTABLETYPE). Co-authored-by: Victor Stinner --- Lib/test/test_descr.py | 6 ++++-- Objects/typeobject.c | 18 +++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 79d6c4b5e72..3cb923ed052 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4763,12 +4763,14 @@ order (MRO) for bases """ "elephant" X.__doc__ = "banana" self.assertEqual(X.__doc__, "banana") + with self.assertRaises(TypeError) as cm: type(list).__dict__["__doc__"].__set__(list, "blah") - self.assertIn("can't set list.__doc__", str(cm.exception)) + self.assertIn("cannot set '__doc__' attribute of immutable type 'list'", str(cm.exception)) + with self.assertRaises(TypeError) as cm: type(X).__dict__["__doc__"].__delete__(X) - self.assertIn("can't delete X.__doc__", str(cm.exception)) + self.assertIn("cannot delete '__doc__' attribute of immutable type 'X'", str(cm.exception)) self.assertEqual(X.__doc__, "banana") def test_qualname(self): diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0f7f280bca0..621bb0ca930 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -466,14 +466,16 @@ static PyMemberDef type_members[] = { static int check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name) { - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { PyErr_Format(PyExc_TypeError, - "can't set %s.%s", type->tp_name, name); + "cannot set '%s' attribute of immutable type '%s'", + name, type->tp_name); return 0; } if (!value) { PyErr_Format(PyExc_TypeError, - "can't delete %s.%s", type->tp_name, name); + "cannot delete '%s' attribute of immutable type '%s'", + name, type->tp_name); return 0; } @@ -978,8 +980,10 @@ type_get_annotations(PyTypeObject *type, void *context) static int type_set_annotations(PyTypeObject *type, PyObject *value, void *context) { - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format(PyExc_TypeError, "can't set attributes of built-in/extension type '%s'", type->tp_name); + if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { + PyErr_Format(PyExc_TypeError, + "cannot set '__annotations__' attribute of immutable type '%s'", + type->tp_name); return -1; } @@ -3953,8 +3957,8 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { PyErr_Format( PyExc_TypeError, - "can't set attributes of built-in/extension type '%s'", - type->tp_name); + "cannot set %R attribute of immutable type '%s'", + name, type->tp_name); return -1; } if (PyUnicode_Check(name)) {