From e44e507b0e60de842f57ca79b45696dd263f257f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lemburg?= Date: Mon, 18 Sep 2000 16:20:57 +0000 Subject: PyObject_SetAttr() and PyObject_GetAttr() now also accept Unicode objects for the attribute name. Unicode objects are converted to a string using the default encoding before trying the lookup. Note that previously it was allowed to pass arbitrary objects as attribute name in case the tp_getattro/setattro slots were defined. This patch fixes this by applying an explicit string check first: all uses of these slots expect string objects and do not check for the type resulting in a core dump. The tp_getattro/setattro are still useful as optimization for lookups using interned string objects though. This patch fixes bug #113829. --- Objects/object.c | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/Objects/object.c b/Objects/object.c index 150f357..3323906 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -703,17 +703,31 @@ PyObject_SetAttrString(PyObject *v, char *name, PyObject *w) } } +/* Internal API needed by PyObject_GetAttr(): */ +extern +PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode, + const char *errors); + PyObject * PyObject_GetAttr(PyObject *v, PyObject *name) { - if (v->ob_type->tp_getattro != NULL) - return (*v->ob_type->tp_getattro)(v, name); + /* The Unicode to string conversion is done here because the + existing tp_getattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = _PyUnicode_AsDefaultEncodedString(name, NULL); + if (name == NULL) + return NULL; + } if (!PyString_Check(name)) { PyErr_SetString(PyExc_TypeError, "attribute name must be string"); return NULL; } + if (v->ob_type->tp_getattro != NULL) + return (*v->ob_type->tp_getattro)(v, name); + else return PyObject_GetAttrString(v, PyString_AS_STRING(name)); } @@ -733,20 +747,32 @@ int PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) { int err; - Py_INCREF(name); - if (PyString_Check(name)) - PyString_InternInPlace(&name); - if (v->ob_type->tp_setattro != NULL) - err = (*v->ob_type->tp_setattro)(v, name, value); - else if (PyString_Check(name)) { - err = PyObject_SetAttrString( - v, PyString_AS_STRING(name), value); + + /* The Unicode to string conversion is done here because the + existing tp_setattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (name == NULL) + return -1; } - else { + else + Py_INCREF(name); + + if (!PyString_Check(name)){ PyErr_SetString(PyExc_TypeError, "attribute name must be string"); err = -1; } + else { + PyString_InternInPlace(&name); + if (v->ob_type->tp_setattro != NULL) + err = (*v->ob_type->tp_setattro)(v, name, value); + else + err = PyObject_SetAttrString(v, + PyString_AS_STRING(name), value); + } + Py_DECREF(name); return err; } -- cgit v0.12