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.
This commit is contained in:
Victor Stinner 2020-01-30 09:02:14 +01:00 committed by GitHub
parent 5eb8bff7e4
commit 7a1f6c2da4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 16 deletions

View file

@ -51,6 +51,7 @@ extern int _PyFloat_Init(void);
extern PyStatus _Py_HashRandomization_Init(const PyConfig *); extern PyStatus _Py_HashRandomization_Init(const PyConfig *);
extern PyStatus _PyTypes_Init(void); extern PyStatus _PyTypes_Init(void);
extern PyStatus _PyTypes_InitSlotDefs(void);
extern PyStatus _PyImportZip_Init(PyThreadState *tstate); extern PyStatus _PyImportZip_Init(PyThreadState *tstate);
extern PyStatus _PyGC_Init(PyThreadState *tstate); extern PyStatus _PyGC_Init(PyThreadState *tstate);

View file

@ -6,6 +6,7 @@
#include "pycore_initconfig.h" #include "pycore_initconfig.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_pyerrors.h" #include "pycore_pyerrors.h"
#include "pycore_pylifecycle.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "frameobject.h" #include "frameobject.h"
#include "interpreteridobject.h" #include "interpreteridobject.h"
@ -1841,6 +1842,11 @@ PyObject _Py_NotImplementedStruct = {
PyStatus PyStatus
_PyTypes_Init(void) _PyTypes_Init(void)
{ {
PyStatus status = _PyTypes_InitSlotDefs();
if (_PyStatus_EXCEPTION(status)) {
return status;
}
#define INIT_TYPE(TYPE, NAME) \ #define INIT_TYPE(TYPE, NAME) \
do { \ do { \
if (PyType_Ready(TYPE) < 0) { \ if (PyType_Ready(TYPE) < 0) { \

View file

@ -2,6 +2,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_call.h" #include "pycore_call.h"
#include "pycore_initconfig.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_pyerrors.h" #include "pycore_pyerrors.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
@ -6932,7 +6933,8 @@ which incorporates the additional structures used for numbers, sequences and
mappings. Note that multiple names may map to the same slot (e.g. __eq__, mappings. Note that multiple names may map to the same slot (e.g. __eq__,
__ne__ etc. all map to tp_richcompare) and one name may map to multiple slots __ne__ etc. all map to tp_richcompare) and one name may map to multiple slots
(e.g. __str__ affects tp_str as well as tp_repr). The table is terminated with (e.g. __str__ affects tp_str as well as tp_repr). The table is terminated with
an all-zero entry. (This table is further initialized in init_slotdefs().) an all-zero entry. (This table is further initialized in
_PyTypes_InitSlotDefs().)
*/ */
typedef struct wrapperbase slotdef; typedef struct wrapperbase slotdef;
@ -7423,28 +7425,29 @@ update_slots_callback(PyTypeObject *type, void *data)
static int slotdefs_initialized = 0; static int slotdefs_initialized = 0;
/* Initialize the slotdefs table by adding interned string objects for the /* Initialize the slotdefs table by adding interned string objects for the
names. */ names. */
static void PyStatus
init_slotdefs(void) _PyTypes_InitSlotDefs(void)
{ {
slotdef *p; if (slotdefs_initialized) {
return _PyStatus_OK();
}
if (slotdefs_initialized) for (slotdef *p = slotdefs; p->name; p++) {
return;
for (p = slotdefs; p->name; p++) {
/* Slots must be ordered by their offset in the PyHeapTypeObject. */ /* Slots must be ordered by their offset in the PyHeapTypeObject. */
assert(!p[1].name || p->offset <= p[1].offset); assert(!p[1].name || p->offset <= p[1].offset);
p->name_strobj = PyUnicode_InternFromString(p->name); p->name_strobj = PyUnicode_InternFromString(p->name);
if (!p->name_strobj || !PyUnicode_CHECK_INTERNED(p->name_strobj)) if (!p->name_strobj || !PyUnicode_CHECK_INTERNED(p->name_strobj)) {
Py_FatalError("Out of memory interning slotdef names"); return _PyStatus_NO_MEMORY();
}
} }
slotdefs_initialized = 1; slotdefs_initialized = 1;
return _PyStatus_OK();
} }
/* Undo init_slotdefs, releasing the interned strings. */ /* Undo _PyTypes_InitSlotDefs(), releasing the interned strings. */
static void clear_slotdefs(void) static void clear_slotdefs(void)
{ {
slotdef *p; for (slotdef *p = slotdefs; p->name; p++) {
for (p = slotdefs; p->name; p++) {
Py_CLEAR(p->name_strobj); Py_CLEAR(p->name_strobj);
} }
slotdefs_initialized = 0; slotdefs_initialized = 0;
@ -7462,7 +7465,7 @@ update_slot(PyTypeObject *type, PyObject *name)
assert(PyUnicode_CheckExact(name)); assert(PyUnicode_CheckExact(name));
assert(PyUnicode_CHECK_INTERNED(name)); assert(PyUnicode_CHECK_INTERNED(name));
init_slotdefs(); assert(slotdefs_initialized);
pp = ptrs; pp = ptrs;
for (p = slotdefs; p->name; p++) { for (p = slotdefs; p->name; p++) {
if (p->name_strobj == name) if (p->name_strobj == name)
@ -7490,7 +7493,7 @@ fixup_slot_dispatchers(PyTypeObject *type)
{ {
slotdef *p; slotdef *p;
init_slotdefs(); assert(slotdefs_initialized);
for (p = slotdefs; p->name; ) for (p = slotdefs; p->name; )
p = update_one_slot(type, p); p = update_one_slot(type, p);
} }
@ -7503,7 +7506,7 @@ update_all_slots(PyTypeObject* type)
/* Clear the VALID_VERSION flag of 'type' and all its subclasses. */ /* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
PyType_Modified(type); PyType_Modified(type);
init_slotdefs(); assert(slotdefs_initialized);
for (p = slotdefs; p->name; p++) { for (p = slotdefs; p->name; p++) {
/* update_slot returns int but can't actually fail */ /* update_slot returns int but can't actually fail */
update_slot(type, p->name_strobj); update_slot(type, p->name_strobj);
@ -7663,7 +7666,7 @@ add_operators(PyTypeObject *type)
PyObject *descr; PyObject *descr;
void **ptr; void **ptr;
init_slotdefs(); assert(slotdefs_initialized);
for (p = slotdefs; p->name; p++) { for (p = slotdefs; p->name; p++) {
if (p->wrapper == NULL) if (p->wrapper == NULL)
continue; continue;