diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-03-06 00:13:43 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-06 00:13:43 (GMT) |
commit | c656e25667c9acc0d13e5bb16d3df2938d0f614b (patch) | |
tree | 61e424b53e6f0b1f5a2d7637fedf47ab5e91962e /Python/preconfig.c | |
parent | 7d2ef3ef5042356aaeaf832ad4204b7dad2e1b8c (diff) | |
download | cpython-c656e25667c9acc0d13e5bb16d3df2938d0f614b.zip cpython-c656e25667c9acc0d13e5bb16d3df2938d0f614b.tar.gz cpython-c656e25667c9acc0d13e5bb16d3df2938d0f614b.tar.bz2 |
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".
Diffstat (limited to 'Python/preconfig.c')
-rw-r--r-- | Python/preconfig.c | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/Python/preconfig.c b/Python/preconfig.c index 6924203..ee9dca4 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -125,15 +125,8 @@ precmdline_clear(_PyPreCmdline *cmdline) void _PyPreConfig_Clear(_PyPreConfig *config) { -#define CLEAR(ATTR) \ - do { \ - PyMem_RawFree(ATTR); \ - ATTR = NULL; \ - } while (0) - - CLEAR(config->allocator); - -#undef CLEAR + PyMem_RawFree(config->allocator); + config->allocator = NULL; } @@ -453,8 +446,7 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline) /* allocator */ if (config->dev_mode && config->allocator == NULL) { - const char *allocator = _PyMem_GetDebugAllocatorsName(); - config->allocator = _PyMem_RawStrdup(allocator); + config->allocator = _PyMem_RawStrdup("debug"); if (config->allocator == NULL) { return _Py_INIT_NO_MEMORY(); } @@ -742,31 +734,56 @@ done: static _PyInitError -_PyPreConfig_Reconfigure(const _PyPreConfig *config) +_PyPreConfig_SetAllocator(_PyPreConfig *config) { - if (config->allocator != NULL) { - const char *allocator = _PyMem_GetAllocatorsName(); - if (allocator == NULL || strcmp(config->allocator, allocator) != 0) { - return _Py_INIT_USER_ERR("cannot modify memory allocator " - "after first Py_Initialize()"); - } + assert(!_PyRuntime.core_initialized); + + PyMemAllocatorEx old_alloc; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + if (_PyMem_SetupAllocators(config->allocator) < 0) { + return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator"); + } + + /* Copy the pre-configuration with the new allocator */ + _PyPreConfig config2 = _PyPreConfig_INIT; + if (_PyPreConfig_Copy(&config2, config) < 0) { + _PyPreConfig_Clear(&config2); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + return _Py_INIT_NO_MEMORY(); } + + /* Free the old config and replace config with config2. Since config now + owns the data, don't free config2. */ + PyMemAllocatorEx new_alloc; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &new_alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + _PyPreConfig_Clear(config); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &new_alloc); + + *config = config2; + return _Py_INIT_OK(); } +/* Write the pre-configuration. + + If the memory allocator is changed, config is re-allocated with new + allocator. So calling _PyPreConfig_Clear(config) is safe after this call. */ _PyInitError -_PyPreConfig_Write(const _PyPreConfig *config) +_PyPreConfig_Write(_PyPreConfig *config) { if (_PyRuntime.core_initialized) { /* bpo-34008: Calling Py_Main() after Py_Initialize() ignores the new configuration. */ - return _PyPreConfig_Reconfigure(config); + return _Py_INIT_OK(); } if (config->allocator != NULL) { - if (_PyMem_SetupAllocators(config->allocator) < 0) { - return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator"); + _PyInitError err = _PyPreConfig_SetAllocator(config); + if (_Py_INIT_FAILED(err)) { + return err; } } |