diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-09-23 16:47:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-23 16:47:29 (GMT) |
commit | 9c42f8cda552694f3b47d6388d4ae84d61731872 (patch) | |
tree | 644cebf8bd718b5726054b4b73bb0b6443adcfc1 /Python | |
parent | 88e6447451fb5525e83e802c66c3e51b4a45bf86 (diff) | |
download | cpython-9c42f8cda552694f3b47d6388d4ae84d61731872.zip cpython-9c42f8cda552694f3b47d6388d4ae84d61731872.tar.gz cpython-9c42f8cda552694f3b47d6388d4ae84d61731872.tar.bz2 |
bpo-38234: Fix _PyConfig_InitPathConfig() (GH-16335)
* _PyConfig_InitPathConfig() now starts by copying the global path
configuration, and then override values set in PyConfig.
* _PyPathConfig_Calculate() implementations no longer override
_PyPathConfig fields which are already computed. For example,
if _PyPathConfig.prefix is not NULL, leave it unchanged.
* If Py_SetPath() has been called, _PyConfig_InitPathConfig() doesn't
call _PyPathConfig_Calculate() anymore.
* _PyPathConfig_Calculate() no longer uses PyConfig,
except to initialize PyCalculatePath structure.
* pathconfig_calculate(): remove useless temporary
"_PyPathConfig new_config" variable.
* calculate_module_search_path(): remove hack to workaround memory
allocation failure, call Py_FatalError() instead.
* Fix get_program_full_path(): handle memory allocation failure.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pathconfig.c | 315 |
1 files changed, 166 insertions, 149 deletions
diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 2d00f4b..7677a15 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -51,12 +51,12 @@ pathconfig_clear(_PyPathConfig *config) ATTR = NULL; \ } while (0) - CLEAR(config->prefix); CLEAR(config->program_full_path); + CLEAR(config->prefix); CLEAR(config->exec_prefix); CLEAR(config->module_search_path); - CLEAR(config->home); CLEAR(config->program_name); + CLEAR(config->home); CLEAR(config->base_executable); #undef CLEAR @@ -64,60 +64,31 @@ pathconfig_clear(_PyPathConfig *config) } -/* Calculate the path configuration: initialize pathconfig from config */ static PyStatus -pathconfig_calculate(_PyPathConfig *pathconfig, const PyConfig *config) +pathconfig_copy(_PyPathConfig *config, const _PyPathConfig *config2) { - PyStatus status; - _PyPathConfig new_config = _PyPathConfig_INIT; - - PyMemAllocatorEx old_alloc; - _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + pathconfig_clear(config); - if (copy_wstr(&new_config.module_search_path, - _Py_path_config.module_search_path) < 0) - { - status = _PyStatus_NO_MEMORY(); - goto error; - } - - /* Calculate program_full_path, prefix, exec_prefix, - dll_path (Windows), and module_search_path */ - status = _PyPathConfig_Calculate(&new_config, config); - if (_PyStatus_EXCEPTION(status)) { - goto error; - } - - /* Copy home and program_name from config */ - if (copy_wstr(&new_config.home, config->home) < 0) { - status = _PyStatus_NO_MEMORY(); - goto error; - } - if (copy_wstr(&new_config.program_name, config->program_name) < 0) { - status = _PyStatus_NO_MEMORY(); - goto error; - } - if (config->base_executable) { - PyMem_RawFree(new_config.base_executable); - if (copy_wstr(&new_config.base_executable, - config->base_executable) < 0) { - status = _PyStatus_NO_MEMORY(); - goto error; - } - } - - pathconfig_clear(pathconfig); - *pathconfig = new_config; +#define COPY_ATTR(ATTR) \ + do { \ + if (copy_wstr(&config->ATTR, config2->ATTR) < 0) { \ + return _PyStatus_NO_MEMORY(); \ + } \ + } while (0) - status = _PyStatus_OK(); - goto done; + COPY_ATTR(program_full_path); + COPY_ATTR(prefix); + COPY_ATTR(exec_prefix); + COPY_ATTR(module_search_path); + COPY_ATTR(program_name); + COPY_ATTR(home); + config->isolated = config2->isolated; + config->site_import = config2->site_import; + COPY_ATTR(base_executable); -error: - pathconfig_clear(&new_config); +#undef COPY_ATTR -done: - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - return status; + return _PyStatus_OK(); } @@ -168,7 +139,7 @@ _PyWideStringList_Join(const PyWideStringList *list, wchar_t sep) } -/* Set the global path configuration from config. */ +/* Initialize _Py_dll_path on Windows. Do nothing on other platforms. */ PyStatus _PyPathConfig_Init(void) { @@ -194,47 +165,39 @@ _PyPathConfig_Init(void) static PyStatus -pathconfig_global_init_from_config(const PyConfig *config) +pathconfig_set_from_config(_PyPathConfig *pathconfig, const PyConfig *config) { PyStatus status; PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - _PyPathConfig pathconfig = _PyPathConfig_INIT; - - pathconfig.module_search_path = _PyWideStringList_Join(&config->module_search_paths, DELIM); - if (pathconfig.module_search_path == NULL) { - goto no_memory; + if (config->module_search_paths_set) { + pathconfig->module_search_path = _PyWideStringList_Join(&config->module_search_paths, DELIM); + if (pathconfig->module_search_path == NULL) { + goto no_memory; + } } - if (copy_wstr(&pathconfig.program_full_path, config->executable) < 0) { - goto no_memory; - } - if (copy_wstr(&pathconfig.prefix, config->prefix) < 0) { - goto no_memory; - } - if (copy_wstr(&pathconfig.exec_prefix, config->exec_prefix) < 0) { - goto no_memory; - } - if (copy_wstr(&pathconfig.program_name, config->program_name) < 0) { - goto no_memory; - } - if (copy_wstr(&pathconfig.home, config->home) < 0) { - goto no_memory; - } - if (copy_wstr(&pathconfig.base_executable, config->base_executable) < 0) { - goto no_memory; - } +#define COPY_CONFIG(PATH_ATTR, CONFIG_ATTR) \ + if (config->CONFIG_ATTR) { \ + if (copy_wstr(&pathconfig->PATH_ATTR, config->CONFIG_ATTR) < 0) { \ + goto no_memory; \ + } \ + } - pathconfig_clear(&_Py_path_config); - /* Steal new_config strings; don't clear new_config */ - _Py_path_config = pathconfig; + COPY_CONFIG(base_executable, base_executable); + COPY_CONFIG(program_full_path, executable); + COPY_CONFIG(prefix, prefix); + COPY_CONFIG(exec_prefix, exec_prefix); + COPY_CONFIG(program_name, program_name); + COPY_CONFIG(home, home); + +#undef COPY_CONFIG status = _PyStatus_OK(); goto done; no_memory: - pathconfig_clear(&pathconfig); status = _PyStatus_NO_MEMORY(); done: @@ -283,6 +246,61 @@ config_init_module_search_paths(PyConfig *config, _PyPathConfig *pathconfig) } +/* Calculate the path configuration: + + - exec_prefix + - module_search_path + - prefix + - program_full_path + + On Windows, more fields are calculated: + + - base_executable + - isolated + - site_import + + On other platforms, isolated and site_import are left unchanged, and + _PyConfig_InitPathConfig() copies executable to base_executable (if it's not + set). + + Priority, highest to lowest: + + - PyConfig + - _Py_path_config: set by Py_SetPath(), Py_SetPythonHome() + and Py_SetProgramName() + - _PyPathConfig_Calculate() +*/ +static PyStatus +pathconfig_calculate(_PyPathConfig *pathconfig, const PyConfig *config) +{ + PyStatus status; + + PyMemAllocatorEx old_alloc; + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + status = pathconfig_copy(pathconfig, &_Py_path_config); + if (_PyStatus_EXCEPTION(status)) { + goto done; + } + + status = pathconfig_set_from_config(pathconfig, config); + if (_PyStatus_EXCEPTION(status)) { + goto done; + } + + if (_Py_path_config.module_search_path == NULL) { + status = _PyPathConfig_Calculate(pathconfig, config); + } + else { + /* Py_SetPath() has been called: avoid _PyPathConfig_Calculate() */ + } + +done: + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + return status; +} + + static PyStatus config_calculate_pathconfig(PyConfig *config) { @@ -291,42 +309,28 @@ config_calculate_pathconfig(PyConfig *config) status = pathconfig_calculate(&pathconfig, config); if (_PyStatus_EXCEPTION(status)) { - goto error; + goto done; } if (!config->module_search_paths_set) { status = config_init_module_search_paths(config, &pathconfig); if (_PyStatus_EXCEPTION(status)) { - goto error; - } - } - - if (config->executable == NULL) { - if (copy_wstr(&config->executable, - pathconfig.program_full_path) < 0) { - goto no_memory; - } - } - - if (config->prefix == NULL) { - if (copy_wstr(&config->prefix, pathconfig.prefix) < 0) { - goto no_memory; + goto done; } } - if (config->exec_prefix == NULL) { - if (copy_wstr(&config->exec_prefix, - pathconfig.exec_prefix) < 0) { - goto no_memory; +#define COPY_ATTR(PATH_ATTR, CONFIG_ATTR) \ + if (config->CONFIG_ATTR == NULL) { \ + if (copy_wstr(&config->CONFIG_ATTR, pathconfig.PATH_ATTR) < 0) { \ + goto no_memory; \ + } \ } - } - if (config->base_executable == NULL) { - if (copy_wstr(&config->base_executable, - pathconfig.base_executable) < 0) { - goto no_memory; - } - } + COPY_ATTR(program_full_path, executable); + COPY_ATTR(prefix, prefix); + COPY_ATTR(exec_prefix, exec_prefix); + COPY_ATTR(base_executable, base_executable); +#undef COPY_ATTR if (pathconfig.isolated != -1) { config->isolated = pathconfig.isolated; @@ -335,13 +339,13 @@ config_calculate_pathconfig(PyConfig *config) config->site_import = pathconfig.site_import; } - pathconfig_clear(&pathconfig); - return _PyStatus_OK(); + status = _PyStatus_OK(); + goto done; no_memory: status = _PyStatus_NO_MEMORY(); -error: +done: pathconfig_clear(&pathconfig); return status; } @@ -386,39 +390,55 @@ _PyConfig_InitPathConfig(PyConfig *config) } -static void -pathconfig_global_init(void) +static PyStatus +pathconfig_global_read(_PyPathConfig *pathconfig) { - /* Initialize _Py_dll_path if needed */ - PyStatus status = _PyPathConfig_Init(); - if (_PyStatus_EXCEPTION(status)) { - Py_ExitStatusException(status); - } - - if (_Py_path_config.module_search_path != NULL) { - /* Already initialized */ - return; - } - + PyStatus status; PyConfig config; _PyConfig_InitCompatConfig(&config); + /* Call _PyConfig_InitPathConfig() */ status = PyConfig_Read(&config); if (_PyStatus_EXCEPTION(status)) { - goto error; + goto done; } - status = pathconfig_global_init_from_config(&config); + status = pathconfig_set_from_config(pathconfig, &config); + +done: + PyConfig_Clear(&config); + return status; +} + + +static void +pathconfig_global_init(void) +{ + PyStatus status; + + /* Initialize _Py_dll_path if needed */ + status = _PyPathConfig_Init(); if (_PyStatus_EXCEPTION(status)) { - goto error; + Py_ExitStatusException(status); } - PyConfig_Clear(&config); - return; + if (_Py_path_config.module_search_path == NULL) { + status = pathconfig_global_read(&_Py_path_config); + if (_PyStatus_EXCEPTION(status)) { + Py_ExitStatusException(status); + } + } + else { + /* Global configuration already initialized */ + } -error: - PyConfig_Clear(&config); - Py_ExitStatusException(status); + assert(_Py_path_config.program_full_path != NULL); + assert(_Py_path_config.prefix != NULL); + assert(_Py_path_config.exec_prefix != NULL); + assert(_Py_path_config.module_search_path != NULL); + assert(_Py_path_config.program_name != NULL); + /* home can be NULL */ + assert(_Py_path_config.base_executable != NULL); } @@ -435,30 +455,27 @@ Py_SetPath(const wchar_t *path) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - _PyPathConfig new_config; - new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName()); - int alloc_error = (new_config.program_full_path == NULL); - new_config.prefix = _PyMem_RawWcsdup(L""); - alloc_error |= (new_config.prefix == NULL); - new_config.exec_prefix = _PyMem_RawWcsdup(L""); - alloc_error |= (new_config.exec_prefix == NULL); - new_config.module_search_path = _PyMem_RawWcsdup(path); - alloc_error |= (new_config.module_search_path == NULL); - - /* steal the home and program_name values (to leave them unchanged) */ - new_config.home = _Py_path_config.home; - _Py_path_config.home = NULL; - new_config.program_name = _Py_path_config.program_name; - _Py_path_config.program_name = NULL; - new_config.base_executable = _Py_path_config.base_executable; - _Py_path_config.base_executable = NULL; + /* Getting the program name calls pathconfig_global_init() */ + wchar_t *program_name = _PyMem_RawWcsdup(Py_GetProgramName()); - pathconfig_clear(&_Py_path_config); - _Py_path_config = new_config; + PyMem_RawFree(_Py_path_config.program_full_path); + PyMem_RawFree(_Py_path_config.prefix); + PyMem_RawFree(_Py_path_config.exec_prefix); + PyMem_RawFree(_Py_path_config.module_search_path); + + /* Copy program_name to program_full_path */ + _Py_path_config.program_full_path = program_name; + _Py_path_config.prefix = _PyMem_RawWcsdup(L""); + _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L""); + _Py_path_config.module_search_path = _PyMem_RawWcsdup(path); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - if (alloc_error) { + if (_Py_path_config.program_full_path == NULL + || _Py_path_config.prefix == NULL + || _Py_path_config.exec_prefix == NULL + || _Py_path_config.module_search_path == NULL) + { Py_FatalError("Py_SetPath() failed: out of memory"); } } |