bpo-32030: Add _PyImport_Fini2() (#4737)

PyImport_ExtendInittab() now uses PyMem_RawRealloc() rather than
PyMem_Realloc(). PyImport_ExtendInittab() can be called before
Py_Initialize() whereas only the PyMem_Raw allocator is supposed to
be used before Py_Initialize().

Add _PyImport_Fini2() to release the memory allocated by
PyImport_ExtendInittab() at exit. PyImport_ExtendInittab() now forces
the usage of the default raw allocator, to be able to release memory
in _PyImport_Fini2().

Don't export these functions anymore to be C API, only to
Py_BUILD_CORE:

* _PyExc_Fini()
* _PyImport_Fini()
* _PyGC_DumpShutdownStats()
* _PyGC_Fini()
* _PyType_Fini()
* _Py_HashRandomization_Fini()
This commit is contained in:
Victor Stinner 2017-12-06 18:12:59 +01:00 committed by GitHub
parent 1b4587a246
commit 92a3c6f493
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 35 deletions

View file

@ -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
@ -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 *
@ -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++)
@ -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 */