]> granicus.if.org Git - python/commitdiff
PyObject_SetAttr() and PyObject_GetAttr() now also accept Unicode
authorMarc-André Lemburg <mal@egenix.com>
Mon, 18 Sep 2000 16:20:57 +0000 (16:20 +0000)
committerMarc-André Lemburg <mal@egenix.com>
Mon, 18 Sep 2000 16:20:57 +0000 (16:20 +0000)
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

index 150f3576c6014f86164a37b2812358ca94748f88..33239068045b58038758242c87ee96173dab4fac 100644 (file)
@@ -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;
 }