mirror of
https://github.com/python/cpython.git
synced 2025-10-06 23:21:06 +00:00
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.
This commit is contained in:
parent
1de8098ca6
commit
e44e507b0e
1 changed files with 37 additions and 11 deletions
|
@ -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
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue