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.
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 @@
 	}
 }
 
+/* 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 @@
 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;
 }