Skip to content

Commit c656e25

Browse files
authored
bpo-36142: Add _PyPreConfig_SetAllocator() (GH-12187)
* _PyPreConfig_Write() now reallocates the pre-configuration with the new memory allocator. * It is no longer needed to force the "default raw memory allocator" to clear pre-configuration and core configuration. Simplify the code. * _PyPreConfig_Write() now does nothing if called after Py_Initialize(): no longer check if the allocator is the same. * Remove _PyMem_GetDebugAllocatorsName(): dev mode sets again allocator to "debug".
1 parent 7d2ef3e commit c656e25

File tree

7 files changed

+50
-88
lines changed

7 files changed

+50
-88
lines changed

Include/internal/pycore_coreconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ PyAPI_FUNC(int) _PyPreConfig_AsDict(const _PyPreConfig *config,
5959
PyObject *dict);
6060
PyAPI_FUNC(_PyInitError) _PyPreConfig_ReadFromArgv(_PyPreConfig *config,
6161
const _PyArgv *args);
62-
PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config);
62+
PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(_PyPreConfig *config);
6363

6464

6565
/* --- _PyCoreConfig ---------------------------------------------- */

Include/internal/pycore_pymem.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,6 @@ PyAPI_FUNC(int) _PyMem_SetDefaultAllocator(
155155
PyMemAllocatorDomain domain,
156156
PyMemAllocatorEx *old_alloc);
157157

158-
PyAPI_FUNC(const char*) _PyMem_GetDebugAllocatorsName(void);
159-
160158
#ifdef __cplusplus
161159
}
162160
#endif

Lib/test/test_embed.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
336336
'legacy_windows_fs_encoding': 0,
337337
'legacy_windows_stdio': 0,
338338
})
339-
DEBUG_ALLOCATOR = 'pymalloc_debug' if support.with_pymalloc() else 'malloc_debug'
340339

341340
# main config
342341
COPY_MAIN_CONFIG = (
@@ -589,15 +588,15 @@ def test_init_env(self):
589588

590589
def test_init_env_dev_mode(self):
591590
config = dict(self.INIT_ENV_CONFIG,
592-
allocator=self.DEBUG_ALLOCATOR,
591+
allocator='debug',
593592
dev_mode=1)
594593
self.check_config("init_env_dev_mode", config)
595594

596595
def test_init_dev_mode(self):
597596
config = {
598597
'dev_mode': 1,
599598
'faulthandler': 1,
600-
'allocator': self.DEBUG_ALLOCATOR,
599+
'allocator': 'debug',
601600
}
602601
self.check_config("init_dev_mode", config)
603602

Modules/main.c

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -289,17 +289,9 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config,
289289
static _PyInitError
290290
preconfig_read_write(_PyPreConfig *config, const _PyArgv *args)
291291
{
292-
_PyInitError err;
293-
294-
PyMemAllocatorEx old_alloc;
295-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
296-
297292
_PyPreConfig_GetGlobalConfig(config);
298293

299-
err = _PyPreConfig_ReadFromArgv(config, args);
300-
301-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
302-
294+
_PyInitError err = _PyPreConfig_ReadFromArgv(config, args);
303295
if (_Py_INIT_FAILED(err)) {
304296
return err;
305297
}
@@ -312,17 +304,9 @@ static _PyInitError
312304
config_read_write(_PyCoreConfig *config, const _PyArgv *args,
313305
const _PyPreConfig *preconfig)
314306
{
315-
_PyInitError err;
316-
317-
PyMemAllocatorEx old_alloc;
318-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
319-
320307
_PyCoreConfig_GetGlobalConfig(config);
321308

322-
err = _PyCoreConfig_ReadFromArgv(config, args, preconfig);
323-
324-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
325-
309+
_PyInitError err = _PyCoreConfig_ReadFromArgv(config, args, preconfig);
326310
if (_Py_INIT_FAILED(err)) {
327311
return err;
328312
}
@@ -355,7 +339,6 @@ static _PyInitError
355339
pymain_init(const _PyArgv *args, PyInterpreterState **interp_p)
356340
{
357341
_PyInitError err;
358-
PyMemAllocatorEx old_alloc;
359342

360343
err = _PyRuntime_Initialize();
361344
if (_Py_INIT_FAILED(err)) {
@@ -402,12 +385,8 @@ pymain_init(const _PyArgv *args, PyInterpreterState **interp_p)
402385
err = _Py_INIT_OK();
403386

404387
done:
405-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
406-
407388
_PyPreConfig_Clear(preconfig);
408389
_PyCoreConfig_Clear(config);
409-
410-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
411390
return err;
412391
}
413392

Objects/obmalloc.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,6 @@ static PyMemAllocatorEx _PyObject = PYOBJ_ALLOC;
221221
#endif
222222

223223

224-
/* Get the effective name of "debug" memory allocators,
225-
as if _PyMem_GetAllocatorsName() is called after
226-
_PyMem_SetupAllocators("debug"). */
227-
const char*
228-
_PyMem_GetDebugAllocatorsName(void)
229-
{
230-
#ifdef WITH_PYMALLOC
231-
return "pymalloc_debug";
232-
#else
233-
return "malloc_debug";
234-
#endif
235-
}
236-
237-
238224
static int
239225
pymem_set_default_allocator(PyMemAllocatorDomain domain, int debug,
240226
PyMemAllocatorEx *old_alloc)

Python/preconfig.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,8 @@ precmdline_clear(_PyPreCmdline *cmdline)
125125
void
126126
_PyPreConfig_Clear(_PyPreConfig *config)
127127
{
128-
#define CLEAR(ATTR) \
129-
do { \
130-
PyMem_RawFree(ATTR); \
131-
ATTR = NULL; \
132-
} while (0)
133-
134-
CLEAR(config->allocator);
135-
136-
#undef CLEAR
128+
PyMem_RawFree(config->allocator);
129+
config->allocator = NULL;
137130
}
138131

139132

@@ -453,8 +446,7 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
453446

454447
/* allocator */
455448
if (config->dev_mode && config->allocator == NULL) {
456-
const char *allocator = _PyMem_GetDebugAllocatorsName();
457-
config->allocator = _PyMem_RawStrdup(allocator);
449+
config->allocator = _PyMem_RawStrdup("debug");
458450
if (config->allocator == NULL) {
459451
return _Py_INIT_NO_MEMORY();
460452
}
@@ -742,31 +734,56 @@ _PyPreConfig_ReadFromArgv(_PyPreConfig *config, const _PyArgv *args)
742734

743735

744736
static _PyInitError
745-
_PyPreConfig_Reconfigure(const _PyPreConfig *config)
737+
_PyPreConfig_SetAllocator(_PyPreConfig *config)
746738
{
747-
if (config->allocator != NULL) {
748-
const char *allocator = _PyMem_GetAllocatorsName();
749-
if (allocator == NULL || strcmp(config->allocator, allocator) != 0) {
750-
return _Py_INIT_USER_ERR("cannot modify memory allocator "
751-
"after first Py_Initialize()");
752-
}
739+
assert(!_PyRuntime.core_initialized);
740+
741+
PyMemAllocatorEx old_alloc;
742+
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
743+
744+
if (_PyMem_SetupAllocators(config->allocator) < 0) {
745+
return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
746+
}
747+
748+
/* Copy the pre-configuration with the new allocator */
749+
_PyPreConfig config2 = _PyPreConfig_INIT;
750+
if (_PyPreConfig_Copy(&config2, config) < 0) {
751+
_PyPreConfig_Clear(&config2);
752+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
753+
return _Py_INIT_NO_MEMORY();
753754
}
755+
756+
/* Free the old config and replace config with config2. Since config now
757+
owns the data, don't free config2. */
758+
PyMemAllocatorEx new_alloc;
759+
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
760+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
761+
_PyPreConfig_Clear(config);
762+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
763+
764+
*config = config2;
765+
754766
return _Py_INIT_OK();
755767
}
756768

757769

770+
/* Write the pre-configuration.
771+
772+
If the memory allocator is changed, config is re-allocated with new
773+
allocator. So calling _PyPreConfig_Clear(config) is safe after this call. */
758774
_PyInitError
759-
_PyPreConfig_Write(const _PyPreConfig *config)
775+
_PyPreConfig_Write(_PyPreConfig *config)
760776
{
761777
if (_PyRuntime.core_initialized) {
762778
/* bpo-34008: Calling Py_Main() after Py_Initialize() ignores
763779
the new configuration. */
764-
return _PyPreConfig_Reconfigure(config);
780+
return _Py_INIT_OK();
765781
}
766782

767783
if (config->allocator != NULL) {
768-
if (_PyMem_SetupAllocators(config->allocator) < 0) {
769-
return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
784+
_PyInitError err = _PyPreConfig_SetAllocator(config);
785+
if (_Py_INIT_FAILED(err)) {
786+
return err;
770787
}
771788
}
772789

Python/pylifecycle.c

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -716,21 +716,14 @@ _Py_InitializeCore_impl(PyInterpreterState **interp_p,
716716
static _PyInitError
717717
pyinit_preconfig(_PyPreConfig *preconfig, const _PyPreConfig *src_preconfig)
718718
{
719-
_PyInitError err;
720-
PyMemAllocatorEx old_alloc;
721-
722719
/* Set LC_CTYPE to the user preferred locale */
723720
_Py_SetLocaleFromEnv(LC_CTYPE);
724721

725-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
726-
if (_PyPreConfig_Copy(preconfig, src_preconfig) >= 0) {
727-
err = _PyPreConfig_Read(preconfig);
722+
if (_PyPreConfig_Copy(preconfig, src_preconfig) < 0) {
723+
return _Py_INIT_ERR("failed to copy pre config");
728724
}
729-
else {
730-
err = _Py_INIT_ERR("failed to copy pre config");
731-
}
732-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
733725

726+
_PyInitError err = _PyPreConfig_Read(preconfig);
734727
if (_Py_INIT_FAILED(err)) {
735728
return err;
736729
}
@@ -743,21 +736,15 @@ static _PyInitError
743736
pyinit_coreconfig(_PyCoreConfig *config, const _PyCoreConfig *src_config,
744737
PyInterpreterState **interp_p)
745738
{
746-
PyMemAllocatorEx old_alloc;
747-
_PyInitError err;
748739

749740
/* Set LC_CTYPE to the user preferred locale */
750741
_Py_SetLocaleFromEnv(LC_CTYPE);
751742

752-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
753-
if (_PyCoreConfig_Copy(config, src_config) >= 0) {
754-
err = _PyCoreConfig_Read(config, NULL);
755-
}
756-
else {
757-
err = _Py_INIT_ERR("failed to copy core config");
743+
if (_PyCoreConfig_Copy(config, src_config) < 0) {
744+
return _Py_INIT_ERR("failed to copy core config");
758745
}
759-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
760746

747+
_PyInitError err = _PyCoreConfig_Read(config, NULL);
761748
if (_Py_INIT_FAILED(err)) {
762749
return err;
763750
}
@@ -792,7 +779,6 @@ _PyInitError
792779
_Py_InitializeCore(PyInterpreterState **interp_p,
793780
const _PyCoreConfig *src_config)
794781
{
795-
PyMemAllocatorEx old_alloc;
796782
_PyInitError err;
797783

798784
assert(src_config != NULL);
@@ -807,10 +793,7 @@ _Py_InitializeCore(PyInterpreterState **interp_p,
807793
err = pyinit_coreconfig(&local_config, src_config, interp_p);
808794

809795
done:
810-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
811796
_PyCoreConfig_Clear(&local_config);
812-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
813-
814797
return err;
815798
}
816799

0 commit comments

Comments
 (0)