From 8afa7fa51064848d826e4eb8a2bd46cf7f730b0f Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 30 Oct 2012 23:51:03 -0400 Subject: don't shadow the __qualname__ descriptor with __qualname__ in the class's __dict__ (closes #16271) --- Lib/test/test_descr.py | 8 ++++---- Misc/NEWS | 3 +++ Objects/typeobject.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 079f60b..21c7b8c 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4506,7 +4506,7 @@ order (MRO) for bases """ ns = {'__qualname__': 'some.name'} tp = type('Foo', (), ns) self.assertEqual(tp.__qualname__, 'some.name') - self.assertEqual(tp.__dict__['__qualname__'], 'some.name') + self.assertNotIn('__qualname__', tp.__dict__) self.assertEqual(ns, {'__qualname__': 'some.name'}) ns = {'__qualname__': 1} @@ -4564,7 +4564,7 @@ class DictProxyTests(unittest.TestCase): keys = list(it) keys.sort() self.assertEqual(keys, ['__dict__', '__doc__', '__module__', - '__qualname__', '__weakref__', 'meth']) + '__weakref__', 'meth']) @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __local__') @@ -4573,7 +4573,7 @@ class DictProxyTests(unittest.TestCase): it = self.C.__dict__.values() self.assertNotIsInstance(it, list) values = list(it) - self.assertEqual(len(values), 6) + self.assertEqual(len(values), 5) @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __local__') @@ -4584,7 +4584,7 @@ class DictProxyTests(unittest.TestCase): keys = [item[0] for item in it] keys.sort() self.assertEqual(keys, ['__dict__', '__doc__', '__module__', - '__qualname__', '__weakref__', 'meth']) + '__weakref__', 'meth']) def test_dict_type_with_metaclass(self): # Testing type of __dict__ when metaclass set... diff --git a/Misc/NEWS b/Misc/NEWS index 44ae5f0..726d1f7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.3.1? Core and Builtins ----------------- +- Issue #16271: Fix strange bugs that resulted from __qualname__ appearing in a + class's __dict__ and on type. + - Issue #16197: Update winreg docstrings and documentation to match code. Patch by Zachary Ware. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5d625a2..9f0d13e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2250,11 +2250,10 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) goto error; } } - else { - qualname = et->ht_name; - } - Py_INCREF(qualname); - et->ht_qualname = qualname; + et->ht_qualname = qualname ? qualname : et->ht_name; + Py_INCREF(et->ht_qualname); + if (qualname != NULL && PyDict_DelItem(dict, PyId___qualname__.object) < 0) + goto error; /* Set tp_doc to a copy of dict['__doc__'], if the latter is there and is a string. The __doc__ accessor will first look for tp_doc; -- cgit v0.12 From 2c05a2e01b18e9d10cd153308c4866909631e8c0 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 31 Oct 2012 00:01:15 -0400 Subject: do safety checks on __qualname__ assignment --- Lib/test/test_descr.py | 8 ++++++++ Misc/NEWS | 3 +++ Objects/typeobject.c | 2 ++ 3 files changed, 13 insertions(+) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 21c7b8c..b5a10ed 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4502,6 +4502,14 @@ order (MRO) for bases """ self.assertEqual(float.real.__qualname__, 'float.real') self.assertEqual(int.__add__.__qualname__, 'int.__add__') + class X: + pass + with self.assertRaises(TypeError): + del X.__qualname__ + + self.assertRaises(TypeError, type.__dict__['__qualname__'].__set__, + str, 'Oink') + def test_qualname_dict(self): ns = {'__qualname__': 'some.name'} tp = type('Foo', (), ns) diff --git a/Misc/NEWS b/Misc/NEWS index 726d1f7..347885f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.3.1? Core and Builtins ----------------- +- Fix segfaults on setting __qualname__ on builtin types and attempting to + delete it on any type. + - Issue #16271: Fix strange bugs that resulted from __qualname__ appearing in a class's __dict__ and on type. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9f0d13e..413c7da 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -311,6 +311,8 @@ type_set_qualname(PyTypeObject *type, PyObject *value, void *context) { PyHeapTypeObject* et; + if (!check_set_special_type_attr(type, value, "__qualname__")) + return -1; if (!PyUnicode_Check(value)) { PyErr_Format(PyExc_TypeError, "can only assign string to %s.__qualname__, not '%s'", -- cgit v0.12