Skip to content
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

gh-81057: Move PyImport_Inittab to _PyRuntimeState #99402

Merged
merged 5 commits into from
Nov 12, 2022
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/cpython/import.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct _inittab {
const char *name; /* ASCII encoded string */
PyObject* (*initfunc)(void);
};
// This is not used after Py_Initialize() is called.
PyAPI_DATA(struct _inittab *) PyImport_Inittab;
PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab);

Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_import.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ extern "C" {


struct _import_runtime_state {
/* The builtin modules (defined in config.c). */
struct _inittab *inittab;
/* The most recent value assigned to a PyModuleDef.m_base.m_index.
This is incremented each time PyModuleDef_Init() is called,
which is just about every time an extension module is imported.
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc);

/* Various one-time initializers */

extern PyStatus _PyImport_Init(void);
extern PyStatus _PyFaulthandler_Init(int enable);
extern int _PyTraceMalloc_Init(int enable);
extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The docs clearly say that ``PyImport_Inittab``,
:c:func:`PyImport_AppendInittab`, and :c:func:`PyImport_ExtendInittab`
should not be used after :c:func:`Py_Initialize` has been called.
We now enforce this for the two functions. Additionally, the runtime
now uses an internal copy of ``PyImport_Inittab``,
to guard against modification.
64 changes: 60 additions & 4 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ static PyObject *import_add_module(PyThreadState *tstate, PyObject *name);
/* This table is defined in config.c: */
extern struct _inittab _PyImport_Inittab[];

// This is not used after Py_Initialize() is called.
// (See _PyRuntimeState.imports.inittab.)
struct _inittab *PyImport_Inittab = _PyImport_Inittab;
// When we dynamically allocate a larger table for PyImport_ExtendInittab(),
// we track the pointer here so we can deallocate it during finalization.
static struct _inittab *inittab_copy = NULL;

/*[clinic input]
Expand Down Expand Up @@ -218,6 +222,38 @@ _imp_release_lock_impl(PyObject *module)
Py_RETURN_NONE;
}

PyStatus
_PyImport_Init(void)
{
if (_PyRuntime.imports.inittab != NULL) {
return _PyStatus_ERR("global import state already initialized");
}
PyStatus status = _PyStatus_OK();

size_t size;
for (size = 0; PyImport_Inittab[size].name != NULL; size++)
;
size++;

/* Force default raw memory allocator to get a known allocator to be able
to release the memory in _PyImport_Fini() */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

/* Make the copy. */
struct _inittab *copied = PyMem_RawMalloc(size * sizeof(struct _inittab));
if (copied == NULL) {
status = PyStatus_NoMemory();
goto done;
}
memcpy(copied, PyImport_Inittab, size * sizeof(struct _inittab));
_PyRuntime.imports.inittab = copied;

done:
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
return status;
}

static inline void _extensions_cache_clear(void);

void
Expand All @@ -228,6 +264,17 @@ _PyImport_Fini(void)
PyThread_free_lock(import_lock);
import_lock = NULL;
}

/* Use the same memory allocator as _PyImport_Init(). */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

/* Free memory allocated by _PyImport_Init() */
struct _inittab *inittab = _PyRuntime.imports.inittab;
_PyRuntime.imports.inittab = NULL;
PyMem_RawFree(inittab);

PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}

void
Expand Down Expand Up @@ -889,9 +936,10 @@ static int
is_builtin(PyObject *name)
{
int i;
for (i = 0; PyImport_Inittab[i].name != NULL; i++) {
if (_PyUnicode_EqualToASCIIString(name, PyImport_Inittab[i].name)) {
if (PyImport_Inittab[i].initfunc == NULL)
struct _inittab *inittab = _PyRuntime.imports.inittab;
for (i = 0; inittab[i].name != NULL; i++) {
if (_PyUnicode_EqualToASCIIString(name, inittab[i].name)) {
if (inittab[i].initfunc == NULL)
return -1;
else
return 1;
Expand Down Expand Up @@ -984,7 +1032,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
}

PyObject *modules = tstate->interp->modules;
for (struct _inittab *p = PyImport_Inittab; p->name != NULL; p++) {
for (struct _inittab *p = _PyRuntime.imports.inittab; p->name != NULL; p++) {
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
if (p->initfunc == NULL) {
/* Cannot re-init internal module ("sys" or "builtins") */
Expand Down Expand Up @@ -2592,6 +2640,10 @@ PyImport_ExtendInittab(struct _inittab *newtab)
size_t i, n;
int res = 0;

if (_PyRuntime.imports.inittab != NULL) {
Py_FatalError("PyImport_ExtendInittab() may be be called after Py_Initialize()");
}

/* Count the number of entries in both tables */
for (n = 0; newtab[n].name != NULL; n++)
;
Expand Down Expand Up @@ -2636,6 +2688,10 @@ PyImport_AppendInittab(const char *name, PyObject* (*initfunc)(void))
{
struct _inittab newtab[2];

if (_PyRuntime.imports.inittab != NULL) {
Py_FatalError("PyImport_AppendInittab() may be be called after Py_Initialize()");
}

memset(newtab, '\0', sizeof newtab);

newtab[0].name = name;
Expand Down
5 changes: 5 additions & 0 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,11 @@ pycore_init_runtime(_PyRuntimeState *runtime,
return status;
}

status = _PyImport_Init();
if (_PyStatus_EXCEPTION(status)) {
return status;
}

status = _PyInterpreterState_Enable(runtime);
if (_PyStatus_EXCEPTION(status)) {
return status;
Expand Down
5 changes: 3 additions & 2 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2252,8 +2252,9 @@ list_builtin_module_names(void)
if (list == NULL) {
return NULL;
}
for (Py_ssize_t i = 0; PyImport_Inittab[i].name != NULL; i++) {
PyObject *name = PyUnicode_FromString(PyImport_Inittab[i].name);
struct _inittab *inittab = _PyRuntime.imports.inittab;
for (Py_ssize_t i = 0; inittab[i].name != NULL; i++) {
PyObject *name = PyUnicode_FromString(inittab[i].name);
if (name == NULL) {
goto error;
}
Expand Down
2 changes: 0 additions & 2 deletions Tools/c-analyzer/cpython/globals-to-fix.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,6 @@ Python/frozen.c - _PyImport_FrozenAliases -
Python/frozen.c - _PyImport_FrozenBootstrap -
Python/frozen.c - _PyImport_FrozenStdlib -
Python/frozen.c - _PyImport_FrozenTest -
Python/import.c - inittab_copy -
Python/import.c - PyImport_Inittab -
Python/preconfig.c - Py_FileSystemDefaultEncoding -
Python/preconfig.c - Py_HasFileSystemDefaultEncoding -
Python/preconfig.c - Py_FileSystemDefaultEncodeErrors -
Expand Down
2 changes: 2 additions & 0 deletions Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ filename funcname name reason
##################################
# mutable but known to be safe

Python/import.c - inittab_copy -
Python/import.c - PyImport_Inittab -
Python/pylifecycle.c - _PyRuntime -

# All uses of _PyArg_Parser are handled in c-analyzr/cpython/_analyzer.py.
Expand Down