Skip to content

bpo-38631: Avoid Py_FatalError() in init_slotdefs() #18263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern int _PyFloat_Init(void);
extern PyStatus _Py_HashRandomization_Init(const PyConfig *);

extern PyStatus _PyTypes_Init(void);
extern PyStatus _PyTypes_InitSlotDefs(void);
extern PyStatus _PyImportZip_Init(PyThreadState *tstate);
extern PyStatus _PyGC_Init(PyThreadState *tstate);

Expand Down
6 changes: 6 additions & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "pycore_initconfig.h"
#include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pylifecycle.h"
#include "pycore_pystate.h"
#include "frameobject.h"
#include "interpreteridobject.h"
Expand Down Expand Up @@ -1842,6 +1843,11 @@ PyObject _Py_NotImplementedStruct = {
PyStatus
_PyTypes_Init(void)
{
PyStatus status = _PyTypes_InitSlotDefs();
if (_PyStatus_EXCEPTION(status)) {
return status;
}

#define INIT_TYPE(TYPE, NAME) \
do { \
if (PyType_Ready(TYPE) < 0) { \
Expand Down
35 changes: 19 additions & 16 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Python.h"
#include "pycore_call.h"
#include "pycore_initconfig.h"
#include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h"
Expand Down Expand Up @@ -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__,
__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
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;
Expand Down Expand Up @@ -7423,28 +7425,29 @@ update_slots_callback(PyTypeObject *type, void *data)
static int slotdefs_initialized = 0;
/* Initialize the slotdefs table by adding interned string objects for the
names. */
static void
init_slotdefs(void)
PyStatus
_PyTypes_InitSlotDefs(void)
{
slotdef *p;
if (slotdefs_initialized) {
return _PyStatus_OK();
}

if (slotdefs_initialized)
return;
for (p = slotdefs; p->name; p++) {
for (slotdef *p = slotdefs; p->name; p++) {
/* Slots must be ordered by their offset in the PyHeapTypeObject. */
assert(!p[1].name || p->offset <= p[1].offset);
p->name_strobj = PyUnicode_InternFromString(p->name);
if (!p->name_strobj || !PyUnicode_CHECK_INTERNED(p->name_strobj))
Py_FatalError("Out of memory interning slotdef names");
if (!p->name_strobj || !PyUnicode_CHECK_INTERNED(p->name_strobj)) {
return _PyStatus_NO_MEMORY();
}
}
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)
{
slotdef *p;
for (p = slotdefs; p->name; p++) {
for (slotdef *p = slotdefs; p->name; p++) {
Py_CLEAR(p->name_strobj);
}
slotdefs_initialized = 0;
Expand All @@ -7462,7 +7465,7 @@ update_slot(PyTypeObject *type, PyObject *name)
assert(PyUnicode_CheckExact(name));
assert(PyUnicode_CHECK_INTERNED(name));

init_slotdefs();
assert(slotdefs_initialized);
pp = ptrs;
for (p = slotdefs; p->name; p++) {
if (p->name_strobj == name)
Expand Down Expand Up @@ -7490,7 +7493,7 @@ fixup_slot_dispatchers(PyTypeObject *type)
{
slotdef *p;

init_slotdefs();
assert(slotdefs_initialized);
for (p = slotdefs; p->name; )
p = update_one_slot(type, p);
}
Expand All @@ -7503,7 +7506,7 @@ update_all_slots(PyTypeObject* type)
/* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
PyType_Modified(type);

init_slotdefs();
assert(slotdefs_initialized);
for (p = slotdefs; p->name; p++) {
/* update_slot returns int but can't actually fail */
update_slot(type, p->name_strobj);
Expand Down Expand Up @@ -7663,7 +7666,7 @@ add_operators(PyTypeObject *type)
PyObject *descr;
void **ptr;

init_slotdefs();
assert(slotdefs_initialized);
for (p = slotdefs; p->name; p++) {
if (p->wrapper == NULL)
continue;
Expand Down