Skip to content

Commit ebca9fc

Browse files
committed
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.
1 parent d3d8a1d commit ebca9fc

1 file changed

Lines changed: 72 additions & 20 deletions

File tree

Objects/object.c

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,8 +1094,8 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
10941094
if (name == NULL)
10951095
return NULL;
10961096
}
1097+
else
10971098
#endif
1098-
10991099
if (!PyString_Check(name)) {
11001100
PyErr_SetString(PyExc_TypeError,
11011101
"attribute name must be string");
@@ -1207,46 +1207,73 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
12071207
{
12081208
PyTypeObject *tp = obj->ob_type;
12091209
PyObject *descr;
1210+
PyObject *res = NULL;
12101211
descrgetfunc f;
12111212
PyObject **dictptr;
12121213

1214+
#ifdef Py_USING_UNICODE
1215+
/* The Unicode to string conversion is done here because the
1216+
existing tp_setattro slots expect a string object as name
1217+
and we wouldn't want to break those. */
1218+
if (PyUnicode_Check(name)) {
1219+
name = PyUnicode_AsEncodedString(name, NULL, NULL);
1220+
if (name == NULL)
1221+
return NULL;
1222+
}
1223+
else
1224+
#endif
1225+
if (!PyString_Check(name)){
1226+
PyErr_SetString(PyExc_TypeError,
1227+
"attribute name must be string");
1228+
return NULL;
1229+
}
1230+
else
1231+
Py_INCREF(name);
1232+
12131233
if (tp->tp_dict == NULL) {
12141234
if (PyType_Ready(tp) < 0)
1215-
return NULL;
1235+
goto done;
12161236
}
12171237

12181238
descr = _PyType_Lookup(tp, name);
12191239
f = NULL;
12201240
if (descr != NULL) {
12211241
f = descr->ob_type->tp_descr_get;
1222-
if (f != NULL && PyDescr_IsData(descr))
1223-
return f(descr, obj, (PyObject *)obj->ob_type);
1242+
if (f != NULL && PyDescr_IsData(descr)) {
1243+
res = f(descr, obj, (PyObject *)obj->ob_type);
1244+
goto done;
1245+
}
12241246
}
12251247

12261248
dictptr = _PyObject_GetDictPtr(obj);
12271249
if (dictptr != NULL) {
12281250
PyObject *dict = *dictptr;
12291251
if (dict != NULL) {
1230-
PyObject *res = PyDict_GetItem(dict, name);
1252+
res = PyDict_GetItem(dict, name);
12311253
if (res != NULL) {
12321254
Py_INCREF(res);
1233-
return res;
1255+
goto done;
12341256
}
12351257
}
12361258
}
12371259

1238-
if (f != NULL)
1239-
return f(descr, obj, (PyObject *)obj->ob_type);
1260+
if (f != NULL) {
1261+
res = f(descr, obj, (PyObject *)obj->ob_type);
1262+
goto done;
1263+
}
12401264

12411265
if (descr != NULL) {
12421266
Py_INCREF(descr);
1243-
return descr;
1267+
res = descr;
1268+
goto done;
12441269
}
12451270

12461271
PyErr_Format(PyExc_AttributeError,
12471272
"'%.50s' object has no attribute '%.400s'",
12481273
tp->tp_name, PyString_AS_STRING(name));
1249-
return NULL;
1274+
done:
1275+
Py_DECREF(name);
1276+
return res;
12501277
}
12511278

12521279
int
@@ -1256,18 +1283,40 @@ PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
12561283
PyObject *descr;
12571284
descrsetfunc f;
12581285
PyObject **dictptr;
1286+
int res = -1;
1287+
1288+
#ifdef Py_USING_UNICODE
1289+
/* The Unicode to string conversion is done here because the
1290+
existing tp_setattro slots expect a string object as name
1291+
and we wouldn't want to break those. */
1292+
if (PyUnicode_Check(name)) {
1293+
name = PyUnicode_AsEncodedString(name, NULL, NULL);
1294+
if (name == NULL)
1295+
return -1;
1296+
}
1297+
else
1298+
#endif
1299+
if (!PyString_Check(name)){
1300+
PyErr_SetString(PyExc_TypeError,
1301+
"attribute name must be string");
1302+
return -1;
1303+
}
1304+
else
1305+
Py_INCREF(name);
12591306

12601307
if (tp->tp_dict == NULL) {
12611308
if (PyType_Ready(tp) < 0)
1262-
return -1;
1309+
goto done;
12631310
}
12641311

12651312
descr = _PyType_Lookup(tp, name);
12661313
f = NULL;
12671314
if (descr != NULL) {
12681315
f = descr->ob_type->tp_descr_set;
1269-
if (f != NULL && PyDescr_IsData(descr))
1270-
return f(descr, obj, value);
1316+
if (f != NULL && PyDescr_IsData(descr)) {
1317+
res = f(descr, obj, value);
1318+
goto done;
1319+
}
12711320
}
12721321

12731322
dictptr = _PyObject_GetDictPtr(obj);
@@ -1276,35 +1325,38 @@ PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
12761325
if (dict == NULL && value != NULL) {
12771326
dict = PyDict_New();
12781327
if (dict == NULL)
1279-
return -1;
1328+
goto done;
12801329
*dictptr = dict;
12811330
}
12821331
if (dict != NULL) {
1283-
int res;
12841332
if (value == NULL)
12851333
res = PyDict_DelItem(dict, name);
12861334
else
12871335
res = PyDict_SetItem(dict, name, value);
12881336
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
12891337
PyErr_SetObject(PyExc_AttributeError, name);
1290-
return res;
1338+
goto done;
12911339
}
12921340
}
12931341

1294-
if (f != NULL)
1295-
return f(descr, obj, value);
1342+
if (f != NULL) {
1343+
res = f(descr, obj, value);
1344+
goto done;
1345+
}
12961346

12971347
if (descr == NULL) {
12981348
PyErr_Format(PyExc_AttributeError,
12991349
"'%.50s' object has no attribute '%.400s'",
13001350
tp->tp_name, PyString_AS_STRING(name));
1301-
return -1;
1351+
goto done;
13021352
}
13031353

13041354
PyErr_Format(PyExc_AttributeError,
13051355
"'%.50s' object attribute '%.400s' is read-only",
13061356
tp->tp_name, PyString_AS_STRING(name));
1307-
return -1;
1357+
done:
1358+
Py_DECREF(name);
1359+
return res;
13081360
}
13091361

13101362
/* Test a value used as condition, e.g., in a for or if statement.

0 commit comments

Comments
 (0)