PyObject_Generic{Get,Set}Attr(): ensure that the attribute name is a

string object (or a Unicode that's trivially converted to ASCII).

PyObject_GetAttr(): add an 'else' to the Unicode test like
PyObject_SetAttr() already has.
This commit is contained in:
Guido van Rossum 2001-12-04 15:54:53 +00:00
parent d3d8a1df5c
commit ebca9fc1ba

View file

@ -1094,8 +1094,8 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
if (name == NULL) if (name == NULL)
return NULL; return NULL;
} }
else
#endif #endif
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");
@ -1207,46 +1207,73 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
{ {
PyTypeObject *tp = obj->ob_type; PyTypeObject *tp = obj->ob_type;
PyObject *descr; PyObject *descr;
PyObject *res = NULL;
descrgetfunc f; descrgetfunc f;
PyObject **dictptr; PyObject **dictptr;
#ifdef Py_USING_UNICODE
/* 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 NULL;
}
else
#endif
if (!PyString_Check(name)){
PyErr_SetString(PyExc_TypeError,
"attribute name must be string");
return NULL;
}
else
Py_INCREF(name);
if (tp->tp_dict == NULL) { if (tp->tp_dict == NULL) {
if (PyType_Ready(tp) < 0) if (PyType_Ready(tp) < 0)
return NULL; goto done;
} }
descr = _PyType_Lookup(tp, name); descr = _PyType_Lookup(tp, name);
f = NULL; f = NULL;
if (descr != NULL) { if (descr != NULL) {
f = descr->ob_type->tp_descr_get; f = descr->ob_type->tp_descr_get;
if (f != NULL && PyDescr_IsData(descr)) if (f != NULL && PyDescr_IsData(descr)) {
return f(descr, obj, (PyObject *)obj->ob_type); res = f(descr, obj, (PyObject *)obj->ob_type);
goto done;
}
} }
dictptr = _PyObject_GetDictPtr(obj); dictptr = _PyObject_GetDictPtr(obj);
if (dictptr != NULL) { if (dictptr != NULL) {
PyObject *dict = *dictptr; PyObject *dict = *dictptr;
if (dict != NULL) { if (dict != NULL) {
PyObject *res = PyDict_GetItem(dict, name); res = PyDict_GetItem(dict, name);
if (res != NULL) { if (res != NULL) {
Py_INCREF(res); Py_INCREF(res);
return res; goto done;
} }
} }
} }
if (f != NULL) if (f != NULL) {
return f(descr, obj, (PyObject *)obj->ob_type); res = f(descr, obj, (PyObject *)obj->ob_type);
goto done;
}
if (descr != NULL) { if (descr != NULL) {
Py_INCREF(descr); Py_INCREF(descr);
return descr; res = descr;
goto done;
} }
PyErr_Format(PyExc_AttributeError, PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'", "'%.50s' object has no attribute '%.400s'",
tp->tp_name, PyString_AS_STRING(name)); tp->tp_name, PyString_AS_STRING(name));
return NULL; done:
Py_DECREF(name);
return res;
} }
int int
@ -1256,18 +1283,40 @@ PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
PyObject *descr; PyObject *descr;
descrsetfunc f; descrsetfunc f;
PyObject **dictptr; PyObject **dictptr;
int res = -1;
#ifdef Py_USING_UNICODE
/* 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
#endif
if (!PyString_Check(name)){
PyErr_SetString(PyExc_TypeError,
"attribute name must be string");
return -1;
}
else
Py_INCREF(name);
if (tp->tp_dict == NULL) { if (tp->tp_dict == NULL) {
if (PyType_Ready(tp) < 0) if (PyType_Ready(tp) < 0)
return -1; goto done;
} }
descr = _PyType_Lookup(tp, name); descr = _PyType_Lookup(tp, name);
f = NULL; f = NULL;
if (descr != NULL) { if (descr != NULL) {
f = descr->ob_type->tp_descr_set; f = descr->ob_type->tp_descr_set;
if (f != NULL && PyDescr_IsData(descr)) if (f != NULL && PyDescr_IsData(descr)) {
return f(descr, obj, value); res = f(descr, obj, value);
goto done;
}
} }
dictptr = _PyObject_GetDictPtr(obj); dictptr = _PyObject_GetDictPtr(obj);
@ -1276,35 +1325,38 @@ PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
if (dict == NULL && value != NULL) { if (dict == NULL && value != NULL) {
dict = PyDict_New(); dict = PyDict_New();
if (dict == NULL) if (dict == NULL)
return -1; goto done;
*dictptr = dict; *dictptr = dict;
} }
if (dict != NULL) { if (dict != NULL) {
int res;
if (value == NULL) if (value == NULL)
res = PyDict_DelItem(dict, name); res = PyDict_DelItem(dict, name);
else else
res = PyDict_SetItem(dict, name, value); res = PyDict_SetItem(dict, name, value);
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
PyErr_SetObject(PyExc_AttributeError, name); PyErr_SetObject(PyExc_AttributeError, name);
return res; goto done;
} }
} }
if (f != NULL) if (f != NULL) {
return f(descr, obj, value); res = f(descr, obj, value);
goto done;
}
if (descr == NULL) { if (descr == NULL) {
PyErr_Format(PyExc_AttributeError, PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'", "'%.50s' object has no attribute '%.400s'",
tp->tp_name, PyString_AS_STRING(name)); tp->tp_name, PyString_AS_STRING(name));
return -1; goto done;
} }
PyErr_Format(PyExc_AttributeError, PyErr_Format(PyExc_AttributeError,
"'%.50s' object attribute '%.400s' is read-only", "'%.50s' object attribute '%.400s' is read-only",
tp->tp_name, PyString_AS_STRING(name)); tp->tp_name, PyString_AS_STRING(name));
return -1; done:
Py_DECREF(name);
return res;
} }
/* Test a value used as condition, e.g., in a for or if statement. /* Test a value used as condition, e.g., in a for or if statement.