Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 92a3c6f

Browse files
authored
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()
1 parent 1b4587a commit 92a3c6f

File tree

3 files changed

+78
-35
lines changed

3 files changed

+78
-35
lines changed

Include/pylifecycle.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,18 @@ PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
137137
#endif
138138

139139
/* Various internal finalizers */
140-
#ifndef Py_LIMITED_API
140+
141+
#ifdef Py_BUILD_CORE
141142
PyAPI_FUNC(void) _PyExc_Fini(void);
142143
PyAPI_FUNC(void) _PyImport_Fini(void);
144+
PyAPI_FUNC(void) _PyImport_Fini2(void);
145+
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void);
146+
PyAPI_FUNC(void) _PyGC_Fini(void);
147+
PyAPI_FUNC(void) _PyType_Fini(void);
148+
PyAPI_FUNC(void) _Py_HashRandomization_Fini(void);
149+
#endif /* Py_BUILD_CORE */
150+
151+
#ifndef Py_LIMITED_API
143152
PyAPI_FUNC(void) PyMethod_Fini(void);
144153
PyAPI_FUNC(void) PyFrame_Fini(void);
145154
PyAPI_FUNC(void) PyCFunction_Fini(void);
@@ -151,15 +160,11 @@ PyAPI_FUNC(void) PyBytes_Fini(void);
151160
PyAPI_FUNC(void) PyByteArray_Fini(void);
152161
PyAPI_FUNC(void) PyFloat_Fini(void);
153162
PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
154-
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void);
155-
PyAPI_FUNC(void) _PyGC_Fini(void);
156163
PyAPI_FUNC(void) PySlice_Fini(void);
157-
PyAPI_FUNC(void) _PyType_Fini(void);
158-
PyAPI_FUNC(void) _Py_HashRandomization_Fini(void);
159164
PyAPI_FUNC(void) PyAsyncGen_Fini(void);
160165

161166
PyAPI_FUNC(int) _Py_IsFinalizing(void);
162-
#endif
167+
#endif /* !Py_LIMITED_API */
163168

164169
/* Signals */
165170
typedef void (*PyOS_sighandler_t)(int);

Modules/main.c

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -446,17 +446,18 @@ pymain_optlist_clear(_Py_OptList *list)
446446
list->options = NULL;
447447
}
448448

449-
static void
450-
pymain_free_impl(_PyMain *pymain)
451-
{
452-
_Py_CommandLineDetails *cmdline = &pymain->cmdline;
453-
pymain_optlist_clear(&cmdline->warning_options);
454-
pymain_optlist_clear(&cmdline->xoptions);
455-
PyMem_RawFree(cmdline->command);
456449

457-
pymain_optlist_clear(&pymain->env_warning_options);
458-
Py_CLEAR(pymain->main_importer_path);
450+
/* Free global variables which cannot be freed in Py_Finalize():
451+
configuration options set before Py_Initialize() which should
452+
remain valid after Py_Finalize(), since Py_Initialize()/Py_Finalize() can
453+
be called multiple times.
459454
455+
Called with the current memory allocators. */
456+
static void
457+
pymain_free_globals(_PyMain *pymain)
458+
{
459+
_PyPathConfig_Clear(&_Py_path_config);
460+
_PyImport_Fini2();
460461
_PyMainInterpreterConfig_Clear(&pymain->config);
461462

462463
#ifdef __INSURE__
@@ -473,19 +474,33 @@ pymain_free_impl(_PyMain *pymain)
473474
#endif /* __INSURE__ */
474475
}
475476

477+
478+
static void
479+
pymain_free_pymain(_PyMain *pymain)
480+
{
481+
_Py_CommandLineDetails *cmdline = &pymain->cmdline;
482+
pymain_optlist_clear(&cmdline->warning_options);
483+
pymain_optlist_clear(&cmdline->xoptions);
484+
PyMem_RawFree(cmdline->command);
485+
486+
pymain_optlist_clear(&pymain->env_warning_options);
487+
Py_CLEAR(pymain->main_importer_path);
488+
489+
}
490+
476491
static void
477492
pymain_free(_PyMain *pymain)
478493
{
479494
/* Force the allocator used by pymain_parse_cmdline_envvars() */
480495
PyMemAllocatorEx old_alloc;
481496
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
482497

483-
pymain_free_impl(pymain);
498+
pymain_free_pymain(pymain);
499+
pymain_free_globals(pymain);
484500

485501
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
486502
}
487503

488-
489504
static int
490505
pymain_run_main_from_importer(_PyMain *pymain)
491506
{
@@ -1719,13 +1734,6 @@ pymain_impl(_PyMain *pymain)
17191734
pymain->status = 120;
17201735
}
17211736

1722-
/* _PyPathConfig_Clear() cannot be called in Py_FinalizeEx().
1723-
Py_Initialize() and Py_Finalize() can be called multiple times, but it
1724-
must not "forget" parameters set by Py_SetProgramName(), Py_SetPath() or
1725-
Py_SetPythonHome(), whereas _PyPathConfig_Clear() clear all these
1726-
parameters. */
1727-
_PyPathConfig_Clear(&_Py_path_config);
1728-
17291737
return 0;
17301738
}
17311739

Python/import.c

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static PyObject *extensions = NULL;
3030
extern struct _inittab _PyImport_Inittab[];
3131

3232
struct _inittab *PyImport_Inittab = _PyImport_Inittab;
33+
static struct _inittab *inittab_copy = NULL;
3334

3435
/*[clinic input]
3536
module _imp
@@ -285,6 +286,19 @@ _PyImport_Fini(void)
285286
}
286287
}
287288

289+
void
290+
_PyImport_Fini2(void)
291+
{
292+
/* Use the same memory allocator than PyImport_ExtendInittab(). */
293+
PyMemAllocatorEx old_alloc;
294+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
295+
296+
/* Free memory allocated by PyImport_ExtendInittab() */
297+
PyMem_RawFree(inittab_copy);
298+
299+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
300+
}
301+
288302
/* Helper for sys */
289303

290304
PyObject *
@@ -2233,9 +2247,9 @@ PyInit_imp(void)
22332247
int
22342248
PyImport_ExtendInittab(struct _inittab *newtab)
22352249
{
2236-
static struct _inittab *our_copy = NULL;
22372250
struct _inittab *p;
2238-
int i, n;
2251+
Py_ssize_t i, n;
2252+
int res = 0;
22392253

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

2262+
/* Force default raw memory allocator to get a known allocator to be able
2263+
to release the memory in _PyImport_Fini2() */
2264+
PyMemAllocatorEx old_alloc;
2265+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
2266+
22482267
/* Allocate new memory for the combined table */
2249-
p = our_copy;
2250-
PyMem_RESIZE(p, struct _inittab, i+n+1);
2251-
if (p == NULL)
2252-
return -1;
2268+
if ((i + n + 1) <= PY_SSIZE_T_MAX / sizeof(struct _inittab)) {
2269+
size_t size = sizeof(struct _inittab) * (i + n + 1);
2270+
p = PyMem_RawRealloc(inittab_copy, size);
2271+
}
2272+
else {
2273+
p = NULL;
2274+
}
2275+
if (p == NULL) {
2276+
res = -1;
2277+
goto done;
2278+
}
22532279

2254-
/* Copy the tables into the new memory */
2255-
if (our_copy != PyImport_Inittab)
2280+
/* Copy the tables into the new memory at the first call
2281+
to PyImport_ExtendInittab(). */
2282+
if (inittab_copy != PyImport_Inittab) {
22562283
memcpy(p, PyImport_Inittab, (i+1) * sizeof(struct _inittab));
2257-
PyImport_Inittab = our_copy = p;
2258-
memcpy(p+i, newtab, (n+1) * sizeof(struct _inittab));
2284+
}
2285+
memcpy(p + i, newtab, (n + 1) * sizeof(struct _inittab));
2286+
PyImport_Inittab = inittab_copy = p;
22592287

2260-
return 0;
2288+
done:
2289+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
2290+
return res;
22612291
}
22622292

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

0 commit comments

Comments
 (0)