Commit e44e507b authored by Marc-André Lemburg's avatar Marc-André Lemburg

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.
parent 1de8098c
...@@ -703,17 +703,31 @@ PyObject_SetAttrString(PyObject *v, char *name, PyObject *w) ...@@ -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 *
PyObject_GetAttr(PyObject *v, PyObject *name) PyObject_GetAttr(PyObject *v, PyObject *name)
{ {
if (v->ob_type->tp_getattro != NULL) /* The Unicode to string conversion is done here because the
return (*v->ob_type->tp_getattro)(v, name); 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)) { if (!PyString_Check(name)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"attribute name must be string"); "attribute name must be string");
return NULL; 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)); return PyObject_GetAttrString(v, PyString_AS_STRING(name));
} }
...@@ -733,20 +747,32 @@ int ...@@ -733,20 +747,32 @@ int
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
{ {
int err; int err;
Py_INCREF(name);
if (PyString_Check(name)) /* The Unicode to string conversion is done here because the
PyString_InternInPlace(&name); existing tp_setattro slots expect a string object as name
if (v->ob_type->tp_setattro != NULL) and we wouldn't want to break those. */
err = (*v->ob_type->tp_setattro)(v, name, value); if (PyUnicode_Check(name)) {
else if (PyString_Check(name)) { name = PyUnicode_AsEncodedString(name, NULL, NULL);
err = PyObject_SetAttrString( if (name == NULL)
v, PyString_AS_STRING(name), value); return -1;
} }
else { else
Py_INCREF(name);
if (!PyString_Check(name)){
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"attribute name must be string"); "attribute name must be string");
err = -1; 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); Py_DECREF(name);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment