From: Benjamin Peterson Date: Fri, 16 Mar 2012 15:58:46 +0000 (-0500) Subject: check for string attribute names in old-style classes (closes #14334) X-Git-Tag: v2.7.4rc1~960 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dbc52f8a0d3c496e642dbc92c684f873e67f3127;p=python check for string attribute names in old-style classes (closes #14334) --- diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index db75b93479..e5cdf088f4 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -628,6 +628,13 @@ class ClassTests(unittest.TestCase): a = A(hash(A.f.im_func)^(-1)) hash(a.f) + def testAttrSlots(self): + class C: + pass + for c in C, C(): + self.assertRaises(TypeError, type(c).__getattribute__, c, []) + self.assertRaises(TypeError, type(c).__setattr__, c, [], []) + def test_main(): with test_support.check_py3k_warnings( (".+__(get|set|del)slice__ has been removed", DeprecationWarning), diff --git a/Misc/NEWS b/Misc/NEWS index 40c88d9572..471051f665 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,7 +10,8 @@ Core and Builtins ----------------- - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not - passed strings. + passed strings. Also fix segfaults in the __getattribute__ and __setattr__ + methods of old-style classes. - Issue #14161: fix the __repr__ of file objects to escape the file name. diff --git a/Objects/classobject.c b/Objects/classobject.c index 161906ae5d..2c9c21694e 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -225,10 +225,16 @@ static PyObject * class_getattr(register PyClassObject *op, PyObject *name) { register PyObject *v; - register char *sname = PyString_AsString(name); + register char *sname; PyClassObject *klass; descrgetfunc f; + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return NULL; + } + + sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { if (strcmp(sname, "__dict__") == 0) { if (PyEval_GetRestricted()) { @@ -336,6 +342,10 @@ class_setattr(PyClassObject *op, PyObject *name, PyObject *v) "classes are read-only in restricted mode"); return -1; } + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return -1; + } sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { Py_ssize_t n = PyString_Size(name); @@ -699,7 +709,14 @@ static PyObject * instance_getattr1(register PyInstanceObject *inst, PyObject *name) { register PyObject *v; - register char *sname = PyString_AsString(name); + register char *sname; + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return NULL; + } + + sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { if (strcmp(sname, "__dict__") == 0) { if (PyEval_GetRestricted()) { @@ -810,7 +827,14 @@ static int instance_setattr(PyInstanceObject *inst, PyObject *name, PyObject *v) { PyObject *func, *args, *res, *tmp; - char *sname = PyString_AsString(name); + char *sname; + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return -1; + } + + sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { Py_ssize_t n = PyString_Size(name); if (sname[n-1] == '_' && sname[n-2] == '_') {