Skip to content

Commit 7a1f6c2

Browse files
authored
bpo-38631: Avoid Py_FatalError() in init_slotdefs() (GH-18263)
Rename init_slotdefs() to _PyTypes_InitSlotDefs() and add a return value of type PyStatus. The function is now called exactly once from _PyTypes_Init(). Replace calls to init_slotdefs() with an assertion checking that slotdefs is initialized.
1 parent 5eb8bff commit 7a1f6c2

File tree

3 files changed

+26
-16
lines changed

3 files changed

+26
-16
lines changed

Include/internal/pycore_pylifecycle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ extern int _PyFloat_Init(void);
5151
extern PyStatus _Py_HashRandomization_Init(const PyConfig *);
5252

5353
extern PyStatus _PyTypes_Init(void);
54+
extern PyStatus _PyTypes_InitSlotDefs(void);
5455
extern PyStatus _PyImportZip_Init(PyThreadState *tstate);
5556
extern PyStatus _PyGC_Init(PyThreadState *tstate);
5657

Objects/object.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pycore_initconfig.h"
77
#include "pycore_object.h"
88
#include "pycore_pyerrors.h"
9+
#include "pycore_pylifecycle.h"
910
#include "pycore_pystate.h"
1011
#include "frameobject.h"
1112
#include "interpreteridobject.h"
@@ -1841,6 +1842,11 @@ PyObject _Py_NotImplementedStruct = {
18411842
PyStatus
18421843
_PyTypes_Init(void)
18431844
{
1845+
PyStatus status = _PyTypes_InitSlotDefs();
1846+
if (_PyStatus_EXCEPTION(status)) {
1847+
return status;
1848+
}
1849+
18441850
#define INIT_TYPE(TYPE, NAME) \
18451851
do { \
18461852
if (PyType_Ready(TYPE) < 0) { \

Objects/typeobject.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Python.h"
44
#include "pycore_call.h"
5+
#include "pycore_initconfig.h"
56
#include "pycore_object.h"
67
#include "pycore_pyerrors.h"
78
#include "pycore_pystate.h"
@@ -6932,7 +6933,8 @@ which incorporates the additional structures used for numbers, sequences and
69326933
mappings. Note that multiple names may map to the same slot (e.g. __eq__,
69336934
__ne__ etc. all map to tp_richcompare) and one name may map to multiple slots
69346935
(e.g. __str__ affects tp_str as well as tp_repr). The table is terminated with
6935-
an all-zero entry. (This table is further initialized in init_slotdefs().)
6936+
an all-zero entry. (This table is further initialized in
6937+
_PyTypes_InitSlotDefs().)
69366938
*/
69376939

69386940
typedef struct wrapperbase slotdef;
@@ -7423,28 +7425,29 @@ update_slots_callback(PyTypeObject *type, void *data)
74237425
static int slotdefs_initialized = 0;
74247426
/* Initialize the slotdefs table by adding interned string objects for the
74257427
names. */
7426-
static void
7427-
init_slotdefs(void)
7428+
PyStatus
7429+
_PyTypes_InitSlotDefs(void)
74287430
{
7429-
slotdef *p;
7431+
if (slotdefs_initialized) {
7432+
return _PyStatus_OK();
7433+
}
74307434

7431-
if (slotdefs_initialized)
7432-
return;
7433-
for (p = slotdefs; p->name; p++) {
7435+
for (slotdef *p = slotdefs; p->name; p++) {
74347436
/* Slots must be ordered by their offset in the PyHeapTypeObject. */
74357437
assert(!p[1].name || p->offset <= p[1].offset);
74367438
p->name_strobj = PyUnicode_InternFromString(p->name);
7437-
if (!p->name_strobj || !PyUnicode_CHECK_INTERNED(p->name_strobj))
7438-
Py_FatalError("Out of memory interning slotdef names");
7439+
if (!p->name_strobj || !PyUnicode_CHECK_INTERNED(p->name_strobj)) {
7440+
return _PyStatus_NO_MEMORY();
7441+
}
74397442
}
74407443
slotdefs_initialized = 1;
7444+
return _PyStatus_OK();
74417445
}
74427446

7443-
/* Undo init_slotdefs, releasing the interned strings. */
7447+
/* Undo _PyTypes_InitSlotDefs(), releasing the interned strings. */
74447448
static void clear_slotdefs(void)
74457449
{
7446-
slotdef *p;
7447-
for (p = slotdefs; p->name; p++) {
7450+
for (slotdef *p = slotdefs; p->name; p++) {
74487451
Py_CLEAR(p->name_strobj);
74497452
}
74507453
slotdefs_initialized = 0;
@@ -7462,7 +7465,7 @@ update_slot(PyTypeObject *type, PyObject *name)
74627465
assert(PyUnicode_CheckExact(name));
74637466
assert(PyUnicode_CHECK_INTERNED(name));
74647467

7465-
init_slotdefs();
7468+
assert(slotdefs_initialized);
74667469
pp = ptrs;
74677470
for (p = slotdefs; p->name; p++) {
74687471
if (p->name_strobj == name)
@@ -7490,7 +7493,7 @@ fixup_slot_dispatchers(PyTypeObject *type)
74907493
{
74917494
slotdef *p;
74927495

7493-
init_slotdefs();
7496+
assert(slotdefs_initialized);
74947497
for (p = slotdefs; p->name; )
74957498
p = update_one_slot(type, p);
74967499
}
@@ -7503,7 +7506,7 @@ update_all_slots(PyTypeObject* type)
75037506
/* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
75047507
PyType_Modified(type);
75057508

7506-
init_slotdefs();
7509+
assert(slotdefs_initialized);
75077510
for (p = slotdefs; p->name; p++) {
75087511
/* update_slot returns int but can't actually fail */
75097512
update_slot(type, p->name_strobj);
@@ -7663,7 +7666,7 @@ add_operators(PyTypeObject *type)
76637666
PyObject *descr;
76647667
void **ptr;
76657668

7666-
init_slotdefs();
7669+
assert(slotdefs_initialized);
76677670
for (p = slotdefs; p->name; p++) {
76687671
if (p->wrapper == NULL)
76697672
continue;

0 commit comments

Comments
 (0)