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

bpo-32030: Add _PyImport_Fini2() #4737

Merged
merged 1 commit into from
Dec 6, 2017
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
17 changes: 11 additions & 6 deletions Include/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,18 @@ PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
#endif

/* Various internal finalizers */
#ifndef Py_LIMITED_API

#ifdef Py_BUILD_CORE
PyAPI_FUNC(void) _PyExc_Fini(void);
PyAPI_FUNC(void) _PyImport_Fini(void);
PyAPI_FUNC(void) _PyImport_Fini2(void);
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void);
PyAPI_FUNC(void) _PyGC_Fini(void);
PyAPI_FUNC(void) _PyType_Fini(void);
PyAPI_FUNC(void) _Py_HashRandomization_Fini(void);
#endif /* Py_BUILD_CORE */

#ifndef Py_LIMITED_API
PyAPI_FUNC(void) PyMethod_Fini(void);
PyAPI_FUNC(void) PyFrame_Fini(void);
PyAPI_FUNC(void) PyCFunction_Fini(void);
Expand All @@ -151,15 +160,11 @@ PyAPI_FUNC(void) PyBytes_Fini(void);
PyAPI_FUNC(void) PyByteArray_Fini(void);
PyAPI_FUNC(void) PyFloat_Fini(void);
PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void);
PyAPI_FUNC(void) _PyGC_Fini(void);
PyAPI_FUNC(void) PySlice_Fini(void);
PyAPI_FUNC(void) _PyType_Fini(void);
PyAPI_FUNC(void) _Py_HashRandomization_Fini(void);
PyAPI_FUNC(void) PyAsyncGen_Fini(void);

PyAPI_FUNC(int) _Py_IsFinalizing(void);
#endif
#endif /* !Py_LIMITED_API */

/* Signals */
typedef void (*PyOS_sighandler_t)(int);
Expand Down
44 changes: 26 additions & 18 deletions Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,17 +446,18 @@ pymain_optlist_clear(_Py_OptList *list)
list->options = NULL;
}

static void
pymain_free_impl(_PyMain *pymain)
{
_Py_CommandLineDetails *cmdline = &pymain->cmdline;
pymain_optlist_clear(&cmdline->warning_options);
pymain_optlist_clear(&cmdline->xoptions);
PyMem_RawFree(cmdline->command);

pymain_optlist_clear(&pymain->env_warning_options);
Py_CLEAR(pymain->main_importer_path);
/* Free global variables which cannot be freed in Py_Finalize():
configuration options set before Py_Initialize() which should
remain valid after Py_Finalize(), since Py_Initialize()/Py_Finalize() can
be called multiple times.

Called with the current memory allocators. */
static void
pymain_free_globals(_PyMain *pymain)
{
_PyPathConfig_Clear(&_Py_path_config);
_PyImport_Fini2();
_PyMainInterpreterConfig_Clear(&pymain->config);

#ifdef __INSURE__
Expand All @@ -473,19 +474,33 @@ pymain_free_impl(_PyMain *pymain)
#endif /* __INSURE__ */
}


static void
pymain_free_pymain(_PyMain *pymain)
{
_Py_CommandLineDetails *cmdline = &pymain->cmdline;
pymain_optlist_clear(&cmdline->warning_options);
pymain_optlist_clear(&cmdline->xoptions);
PyMem_RawFree(cmdline->command);

pymain_optlist_clear(&pymain->env_warning_options);
Py_CLEAR(pymain->main_importer_path);

}

static void
pymain_free(_PyMain *pymain)
{
/* Force the allocator used by pymain_parse_cmdline_envvars() */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

pymain_free_impl(pymain);
pymain_free_pymain(pymain);
pymain_free_globals(pymain);

PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}


static int
pymain_run_main_from_importer(_PyMain *pymain)
{
Expand Down Expand Up @@ -1719,13 +1734,6 @@ pymain_impl(_PyMain *pymain)
pymain->status = 120;
}

/* _PyPathConfig_Clear() cannot be called in Py_FinalizeEx().
Py_Initialize() and Py_Finalize() can be called multiple times, but it
must not "forget" parameters set by Py_SetProgramName(), Py_SetPath() or
Py_SetPythonHome(), whereas _PyPathConfig_Clear() clear all these
parameters. */
_PyPathConfig_Clear(&_Py_path_config);

return 0;
}

Expand Down
52 changes: 41 additions & 11 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static PyObject *extensions = NULL;
extern struct _inittab _PyImport_Inittab[];

struct _inittab *PyImport_Inittab = _PyImport_Inittab;
static struct _inittab *inittab_copy = NULL;

/*[clinic input]
module _imp
Expand Down Expand Up @@ -285,6 +286,19 @@ _PyImport_Fini(void)
}
}

void
_PyImport_Fini2(void)
{
/* Use the same memory allocator than PyImport_ExtendInittab(). */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

/* Free memory allocated by PyImport_ExtendInittab() */
PyMem_RawFree(inittab_copy);

PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}

/* Helper for sys */

PyObject *
Expand Down Expand Up @@ -2233,9 +2247,9 @@ PyInit_imp(void)
int
PyImport_ExtendInittab(struct _inittab *newtab)
{
static struct _inittab *our_copy = NULL;
struct _inittab *p;
int i, n;
Py_ssize_t i, n;
int res = 0;

/* Count the number of entries in both tables */
for (n = 0; newtab[n].name != NULL; n++)
Expand All @@ -2245,19 +2259,35 @@ PyImport_ExtendInittab(struct _inittab *newtab)
for (i = 0; PyImport_Inittab[i].name != NULL; i++)
;

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

/* Allocate new memory for the combined table */
p = our_copy;
PyMem_RESIZE(p, struct _inittab, i+n+1);
if (p == NULL)
return -1;
if ((i + n + 1) <= PY_SSIZE_T_MAX / sizeof(struct _inittab)) {
size_t size = sizeof(struct _inittab) * (i + n + 1);
p = PyMem_RawRealloc(inittab_copy, size);
}
else {
p = NULL;
}
if (p == NULL) {
res = -1;
goto done;
}

/* Copy the tables into the new memory */
if (our_copy != PyImport_Inittab)
/* Copy the tables into the new memory at the first call
to PyImport_ExtendInittab(). */
if (inittab_copy != PyImport_Inittab) {
memcpy(p, PyImport_Inittab, (i+1) * sizeof(struct _inittab));
PyImport_Inittab = our_copy = p;
memcpy(p+i, newtab, (n+1) * sizeof(struct _inittab));
}
memcpy(p + i, newtab, (n + 1) * sizeof(struct _inittab));
PyImport_Inittab = inittab_copy = p;

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

/* Shorthand to add a single entry given a name and a function */
Expand Down