Skip to content

Commit 31e9908

Browse files
authored
bpo-32030: Fix usage of memory allocators (#4953)
* _Py_InitializeCore() doesn't call _PyMem_SetupAllocators() anymore if the PYTHONMALLOC environment variable is not set. * pymain_cmdline() now sets the allocator to the default, instead of setting the allocator in subfunctions. * Py_SetStandardStreamEncoding() now calls _PyMem_SetDefaultAllocator() to get a known allocator, to be able to release the memory with the same allocator.
1 parent 83cb778 commit 31e9908

File tree

3 files changed

+50
-12
lines changed

3 files changed

+50
-12
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Py_Initialize() doesn't reset the memory allocators to default if the
2+
``PYTHONMALLOC`` environment variable is not set.

‎Modules/main.c‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -649,11 +649,12 @@ pymain_free_raw(_PyMain *pymain)
649649
Py_Initialize()-Py_Finalize() can be called multiple times. */
650650
_PyPathConfig_Clear(&_Py_path_config);
651651

652+
pymain_clear_config(pymain);
653+
652654
/* Force the allocator used by pymain_read_conf() */
653655
PyMemAllocatorEx old_alloc;
654656
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
655657

656-
_PyCoreConfig_Clear(&pymain->config);
657658
pymain_clear_pymain(pymain);
658659

659660
clear_wstrlist(orig_argc, orig_argv);
@@ -1963,11 +1964,6 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline)
19631964
{
19641965
int res = -1;
19651966

1966-
/* Force default allocator, since pymain_free() must use the same allocator
1967-
than this function. */
1968-
PyMemAllocatorEx old_alloc;
1969-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
1970-
19711967
char *oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL));
19721968
if (oldloc == NULL) {
19731969
pymain->err = _Py_INIT_NO_MEMORY();
@@ -2055,7 +2051,6 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline)
20552051
PyMem_RawFree(oldloc);
20562052
}
20572053

2058-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
20592054
return res;
20602055
}
20612056

@@ -2578,6 +2573,15 @@ pymain_cmdline_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline)
25782573
static int
25792574
pymain_cmdline(_PyMain *pymain)
25802575
{
2576+
/* Force default allocator, since pymain_free() and pymain_clear_config()
2577+
must use the same allocator than this function. */
2578+
PyMemAllocatorEx old_alloc;
2579+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
2580+
#ifdef Py_DEBUG
2581+
PyMemAllocatorEx default_alloc;
2582+
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &default_alloc);
2583+
#endif
2584+
25812585
_Py_CommandLineDetails cmdline;
25822586
memset(&cmdline, 0, sizeof(cmdline));
25832587

@@ -2588,6 +2592,14 @@ pymain_cmdline(_PyMain *pymain)
25882592
pymain_set_global_config(pymain, &cmdline);
25892593

25902594
pymain_clear_cmdline(pymain, &cmdline);
2595+
2596+
#ifdef Py_DEBUG
2597+
/* Make sure that PYMEM_DOMAIN_RAW has not been modified */
2598+
PyMemAllocatorEx cur_alloc;
2599+
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &cur_alloc);
2600+
assert(memcmp(&cur_alloc, &default_alloc, sizeof(cur_alloc)) == 0);
2601+
#endif
2602+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
25912603
return res;
25922604
}
25932605

‎Python/pylifecycle.c‎

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
172172
/* This is too late to have any effect */
173173
return -1;
174174
}
175+
176+
int res = 0;
177+
178+
/* Py_SetStandardStreamEncoding() can be called before Py_Initialize(),
179+
but Py_Initialize() can change the allocator. Use a known allocator
180+
to be able to release the memory later. */
181+
PyMemAllocatorEx old_alloc;
182+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
183+
175184
/* Can't call PyErr_NoMemory() on errors, as Python hasn't been
176185
* initialised yet.
177186
*
@@ -182,7 +191,8 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
182191
if (encoding) {
183192
_Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding);
184193
if (!_Py_StandardStreamEncoding) {
185-
return -2;
194+
res = -2;
195+
goto done;
186196
}
187197
}
188198
if (errors) {
@@ -191,7 +201,8 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
191201
if (_Py_StandardStreamEncoding) {
192202
PyMem_RawFree(_Py_StandardStreamEncoding);
193203
}
194-
return -3;
204+
res = -3;
205+
goto done;
195206
}
196207
}
197208
#ifdef MS_WINDOWS
@@ -200,7 +211,11 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
200211
Py_LegacyWindowsStdioFlag = 1;
201212
}
202213
#endif
203-
return 0;
214+
215+
done:
216+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
217+
218+
return res;
204219
}
205220

206221

@@ -597,8 +612,10 @@ _Py_InitializeCore(const _PyCoreConfig *core_config)
597612
return err;
598613
}
599614

600-
if (_PyMem_SetupAllocators(core_config->allocator) < 0) {
601-
return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
615+
if (core_config->allocator != NULL) {
616+
if (_PyMem_SetupAllocators(core_config->allocator) < 0) {
617+
return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
618+
}
602619
}
603620

604621
if (_PyRuntime.initialized) {
@@ -1818,7 +1835,11 @@ init_sys_streams(PyInterpreterState *interp)
18181835
error:
18191836
res = _Py_INIT_ERR("can't initialize sys standard streams");
18201837

1838+
/* Use the same allocator than Py_SetStandardStreamEncoding() */
1839+
PyMemAllocatorEx old_alloc;
18211840
done:
1841+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
1842+
18221843
/* We won't need them anymore. */
18231844
if (_Py_StandardStreamEncoding) {
18241845
PyMem_RawFree(_Py_StandardStreamEncoding);
@@ -1828,6 +1849,9 @@ init_sys_streams(PyInterpreterState *interp)
18281849
PyMem_RawFree(_Py_StandardStreamErrors);
18291850
_Py_StandardStreamErrors = NULL;
18301851
}
1852+
1853+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
1854+
18311855
PyMem_Free(pythonioencoding);
18321856
Py_XDECREF(bimod);
18331857
Py_XDECREF(iomod);

0 commit comments

Comments
 (0)