From 55e67f96de50116ada196f1cbe743e26e45104de Mon Sep 17 00:00:00 2001 From: furkanonder Date: Tue, 6 Jun 2023 00:02:48 +0300 Subject: [PATCH 1/9] Add warning when creating a type using a namespace dictionary with non-string keys. --- Lib/test/test_descr.py | 14 ++++++++++++++ Objects/typeobject.c | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index ad3eefba365856..f417361837dd3b 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4733,6 +4733,20 @@ class X(object): with self.assertRaises(AttributeError): del X.__abstractmethods__ + def test_gh55664(self): + # gh-55664: issue a warning when the + # __dict__ of a class contains non-string keys + with self.assertWarnsRegex(RuntimeWarning, 'MyClass'): + MyClass = type('MyClass', (), {1: 2}) + + class meta(type): + def __new__(mcls, name, bases, ns): + ns[1] = 2 + return super().__new__(mcls, name, bases, ns) + + with self.assertWarnsRegex(RuntimeWarning, 'MyClass'): + MyClass = meta('MyClass', (), {}) + def test_proxy_call(self): class FakeStr: __class__ = str diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0a57991d26251d..1bcc3ed8c26e49 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3794,6 +3794,16 @@ type_new_impl(type_new_ctx *ctx) // Put the proper slots in place fixup_slot_dispatchers(type); + if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) { + PyObject *name_of_class = type_name(type, NULL); + if (name_of_class == NULL) { + goto error; + } + if (PyErr_WarnFormat(NULL, 1, "non-string key in the __dict__ of class %U", name_of_class) == -1) { + goto error; + } + } + if (type_new_set_names(type) < 0) { goto error; } From a87276170e03b04d9e03b4f7c25dfa0da985e1e4 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 19:09:06 +0000 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst new file mode 100644 index 00000000000000..60bce22c7303f7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst @@ -0,0 +1 @@ +Add warning when creating a :class:`type` using a namespace dictionary with non-string keys. Patched by Daniel Urban and Furkan Onder. From 679286eee14333f776d4bf41dc87a6d2cd7db061 Mon Sep 17 00:00:00 2001 From: Furkan Onder Date: Tue, 6 Jun 2023 22:14:12 +0300 Subject: [PATCH 3/9] Update 2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst --- .../2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst index 60bce22c7303f7..438be985496650 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst @@ -1 +1 @@ -Add warning when creating a :class:`type` using a namespace dictionary with non-string keys. Patched by Daniel Urban and Furkan Onder. +Add warning when creating :class:`type` using a namespace dictionary with non-string keys. Patched by Daniel Urban and Furkan Onder. From e2e9591ffd4850170042fc99cc8e0c9d726a9c29 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Wed, 24 Jan 2024 02:10:02 +0300 Subject: [PATCH 4/9] fix leak --- Objects/typeobject.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bf7480293b3b0d..da6ff613f3cbb7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3828,12 +3828,16 @@ type_new_impl(type_new_ctx *ctx) if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) { PyObject *name_of_class = type_name(type, NULL); - if (name_of_class == NULL) { - goto error; - } - if (PyErr_WarnFormat(NULL, 1, "non-string key in the __dict__ of class %U", name_of_class) == -1) { + if (name_of_class == NULL || + PyErr_WarnFormat( + NULL, 1, "non-string key in the __dict__ of class %U", + name_of_class + ) == -1 + ) { + Py_DECREF(name_of_class); goto error; } + Py_DECREF(name_of_class); } if (type_new_set_names(type) < 0) { From ed725ecd151094c5bff55ab9d00ce4fe27672cb5 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Wed, 24 Jan 2024 02:10:38 +0300 Subject: [PATCH 5/9] add assertwarns --- Lib/test/test_descr.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index a274de61c01400..beeab6cb7f254c 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -5165,7 +5165,8 @@ class Base2(object): mykey = 'from Base2' mykey2 = 'from Base2' - X = type('X', (Base,), {MyKey(): 5}) + with self.assertWarnsRegex(RuntimeWarning, 'X'): + X = type('X', (Base,), {MyKey(): 5}) # mykey is read from Base self.assertEqual(X.mykey, 'from Base') # mykey2 is read from Base2 because MyKey.__eq__ has set __bases__ From 9369a5e896136062e71ecb4b7863adc4672987da Mon Sep 17 00:00:00 2001 From: furkanonder Date: Thu, 25 Jan 2024 00:34:31 +0300 Subject: [PATCH 6/9] Prevent crash if name_of_class equals NULL --- Objects/typeobject.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index da6ff613f3cbb7..42fb276e589698 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3828,12 +3828,14 @@ type_new_impl(type_new_ctx *ctx) if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) { PyObject *name_of_class = type_name(type, NULL); - if (name_of_class == NULL || - PyErr_WarnFormat( - NULL, 1, "non-string key in the __dict__ of class %U", - name_of_class - ) == -1 - ) { + if (name_of_class == NULL) { + return NULL; + } + if (PyErr_WarnFormat(NULL, + 1, + "non-string key in the __dict__ of class %U", + name_of_class) == -1) + { Py_DECREF(name_of_class); goto error; } From 054eee3f8f45cb42347221275d9a89b83c9a876f Mon Sep 17 00:00:00 2001 From: furkanonder Date: Thu, 25 Jan 2024 01:56:23 +0300 Subject: [PATCH 7/9] Prevent leak of type --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c217f8664101f8..efba8d2c037342 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3830,7 +3830,7 @@ type_new_impl(type_new_ctx *ctx) if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) { PyObject *name_of_class = type_name(type, NULL); if (name_of_class == NULL) { - return NULL; + goto error; } if (PyErr_WarnFormat(NULL, 1, From 740af75960702c491eb4b153628390ad956c6c32 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Mon, 29 Jan 2024 01:06:13 +0300 Subject: [PATCH 8/9] use type->tp_name in error message --- Objects/typeobject.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index efba8d2c037342..1b19318c80dea3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3828,19 +3828,14 @@ type_new_impl(type_new_ctx *ctx) fixup_slot_dispatchers(type); if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) { - PyObject *name_of_class = type_name(type, NULL); - if (name_of_class == NULL) { - goto error; - } - if (PyErr_WarnFormat(NULL, - 1, - "non-string key in the __dict__ of class %U", - name_of_class) == -1) - { - Py_DECREF(name_of_class); + if (PyErr_WarnFormat( + PyExc_RuntimeWarning, + 1, + "non-string key in the __dict__ of class %.200s", + type->tp_name) == -1) +{ goto error; } - Py_DECREF(name_of_class); } if (type_new_set_names(type) < 0) { From 1a99bf2679dd9d8177c91815693f238c9eff1451 Mon Sep 17 00:00:00 2001 From: furkanonder Date: Mon, 29 Jan 2024 01:08:39 +0300 Subject: [PATCH 9/9] fix curly brace position --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1b19318c80dea3..038bb43a7f9869 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3833,7 +3833,7 @@ type_new_impl(type_new_ctx *ctx) 1, "non-string key in the __dict__ of class %.200s", type->tp_name) == -1) -{ + { goto error; } }