Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e44e507

Browse files
committed
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.
1 parent 1de8098 commit e44e507

1 file changed

Lines changed: 37 additions & 11 deletions

File tree

Objects/object.c

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -703,17 +703,31 @@ PyObject_SetAttrString(PyObject *v, char *name, PyObject *w)
703703
}
704704
}
705705

706+
/* Internal API needed by PyObject_GetAttr(): */
707+
extern
708+
PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode,
709+
const char *errors);
710+
706711
PyObject *
707712
PyObject_GetAttr(PyObject *v, PyObject *name)
708713
{
709-
if (v->ob_type->tp_getattro != NULL)
710-
return (*v->ob_type->tp_getattro)(v, name);
714+
/* The Unicode to string conversion is done here because the
715+
existing tp_getattro slots expect a string object as name
716+
and we wouldn't want to break those. */
717+
if (PyUnicode_Check(name)) {
718+
name = _PyUnicode_AsDefaultEncodedString(name, NULL);
719+
if (name == NULL)
720+
return NULL;
721+
}
711722

712723
if (!PyString_Check(name)) {
713724
PyErr_SetString(PyExc_TypeError,
714725
"attribute name must be string");
715726
return NULL;
716727
}
728+
if (v->ob_type->tp_getattro != NULL)
729+
return (*v->ob_type->tp_getattro)(v, name);
730+
else
717731
return PyObject_GetAttrString(v, PyString_AS_STRING(name));
718732
}
719733

@@ -733,20 +747,32 @@ int
733747
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
734748
{
735749
int err;
736-
Py_INCREF(name);
737-
if (PyString_Check(name))
738-
PyString_InternInPlace(&name);
739-
if (v->ob_type->tp_setattro != NULL)
740-
err = (*v->ob_type->tp_setattro)(v, name, value);
741-
else if (PyString_Check(name)) {
742-
err = PyObject_SetAttrString(
743-
v, PyString_AS_STRING(name), value);
750+
751+
/* The Unicode to string conversion is done here because the
752+
existing tp_setattro slots expect a string object as name
753+
and we wouldn't want to break those. */
754+
if (PyUnicode_Check(name)) {
755+
name = PyUnicode_AsEncodedString(name, NULL, NULL);
756+
if (name == NULL)
757+
return -1;
744758
}
745-
else {
759+
else
760+
Py_INCREF(name);
761+
762+
if (!PyString_Check(name)){
746763
PyErr_SetString(PyExc_TypeError,
747764
"attribute name must be string");
748765
err = -1;
749766
}
767+
else {
768+
PyString_InternInPlace(&name);
769+
if (v->ob_type->tp_setattro != NULL)
770+
err = (*v->ob_type->tp_setattro)(v, name, value);
771+
else
772+
err = PyObject_SetAttrString(v,
773+
PyString_AS_STRING(name), value);
774+
}
775+
750776
Py_DECREF(name);
751777
return err;
752778
}

0 commit comments

Comments
 (0)