Skip to content

Commit 26f9199

Browse files
committed
Close python#18469: Replace PyDict_GetItemString() with _PyDict_GetItemId() in structseq.c
_PyDict_GetItemId() is more efficient: it only builds the Unicode string once. Identifiers (dictionary keys) are now created at Python initialization, and if the creation failed, Python does exit with a fatal error. Before, PyDict_GetItemString() failure was not handled: structseq_new() could call PyObject_GC_NewVar() with a negative size, and structseq_dealloc() could also crash.
1 parent b8f602a commit 26f9199

2 files changed

Lines changed: 23 additions & 5 deletions

File tree

Objects/structseq.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,20 @@ static char unnamed_fields_key[] = "n_unnamed_fields";
1111
/* Fields with this name have only a field index, not a field name.
1212
They are only allowed for indices < n_visible_fields. */
1313
char *PyStructSequence_UnnamedField = "unnamed field";
14+
_Py_IDENTIFIER(n_sequence_fields);
15+
_Py_IDENTIFIER(n_fields);
16+
_Py_IDENTIFIER(n_unnamed_fields);
1417

1518
#define VISIBLE_SIZE(op) Py_SIZE(op)
1619
#define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \
17-
PyDict_GetItemString((tp)->tp_dict, visible_length_key))
20+
_PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields))
1821

1922
#define REAL_SIZE_TP(tp) PyLong_AsLong( \
20-
PyDict_GetItemString((tp)->tp_dict, real_length_key))
23+
_PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields))
2124
#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
2225

2326
#define UNNAMED_FIELDS_TP(tp) PyLong_AsLong( \
24-
PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
27+
_PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields))
2528
#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
2629

2730

@@ -59,7 +62,7 @@ static void
5962
structseq_dealloc(PyStructSequence *obj)
6063
{
6164
Py_ssize_t i, size;
62-
65+
6366
size = REAL_SIZE(obj);
6467
for (i = 0; i < size; ++i) {
6568
Py_XDECREF(obj->ob_item[i]);
@@ -382,9 +385,21 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
382385
PyTypeObject*
383386
PyStructSequence_NewType(PyStructSequence_Desc *desc)
384387
{
385-
PyTypeObject *result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
388+
PyTypeObject *result;
389+
390+
result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
386391
if (result != NULL) {
387392
PyStructSequence_InitType(result, desc);
388393
}
389394
return result;
390395
}
396+
397+
int _PyStructSequence_Init(void)
398+
{
399+
if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL
400+
|| _PyUnicode_FromId(&PyId_n_fields) == NULL
401+
|| _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL)
402+
return -1;
403+
404+
return 0;
405+
}

Python/pythonrun.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ static void call_py_exitfuncs(void);
8686
static void wait_for_thread_shutdown(void);
8787
static void call_ll_exitfuncs(void);
8888
extern int _PyUnicode_Init(void);
89+
extern int _PyStructSequence_Init(void);
8990
extern void _PyUnicode_Fini(void);
9091
extern int _PyLong_Init(void);
9192
extern void PyLong_Fini(void);
@@ -336,6 +337,8 @@ _Py_InitializeEx_Private(int install_sigs, int install_importlib)
336337
/* Init Unicode implementation; relies on the codec registry */
337338
if (_PyUnicode_Init() < 0)
338339
Py_FatalError("Py_Initialize: can't initialize unicode");
340+
if (_PyStructSequence_Init() < 0)
341+
Py_FatalError("Py_Initialize: can't initialize structseq");
339342

340343
bimod = _PyBuiltin_Init();
341344
if (bimod == NULL)

0 commit comments

Comments
 (0)