diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-07-21 00:06:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-21 00:06:16 (GMT) |
commit | b1147e43daeb3c51a63056b489e8d868404d4e22 (patch) | |
tree | c5716fcfca0f90abbc21b291cd51b0ae022759c4 /Python/pathconfig.c | |
parent | 94487d45707772723ef19e86700a40a12743baa1 (diff) | |
download | cpython-b1147e43daeb3c51a63056b489e8d868404d4e22.zip cpython-b1147e43daeb3c51a63056b489e8d868404d4e22.tar.gz cpython-b1147e43daeb3c51a63056b489e8d868404d4e22.tar.bz2 |
bpo-34170: Rework _PyCoreConfig_Read() to avoid side effect (GH-8353)
Rework _PyCoreConfig_Read() function which *reads* core configuration
to not *modify* the path configuration.
A new _PyCoreConfig_SetPathConfig() function now recreates the path
configuration from the core configuration. This function is now
called very late in _Py_InitializeCore(), just before calling
initimport().
Changes:
* Add _PyCoreConfig.dll_path
* Py_SetPath() now fails with a fatal python error on memory
allocation failure.
* Rename _PyPathConfig_Calculate() to _PyPathConfig_Calculate_impl()
* Replace _PyPathConfig_Init() with _PyPathConfig_Calculate(): the
function now requires a _PyPathConfig
* Add _PyPathConfig_SetGlobal() to set the _Py_path_config global
variable.
* Add _PyCoreConfig_InitPathConfig(): compute the path configuration
* Add _PyCoreConfig_SetPathConfig(): set path configuration from core
configuration
* Rename wstrlist_append() to _Py_wstrlist_append()
* _Py_wstrlist_append() now handles integer overflow.
Diffstat (limited to 'Python/pathconfig.c')
-rw-r--r-- | Python/pathconfig.c | 332 |
1 files changed, 304 insertions, 28 deletions
diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 07aa01c..e987df1 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -13,7 +13,23 @@ extern "C" { _PyPathConfig _Py_path_config = _PyPathConfig_INIT; -void +static int +copy_wstr(wchar_t **dst, const wchar_t *src) +{ + if (src != NULL) { + *dst = _PyMem_RawWcsdup(src); + if (*dst == NULL) { + return -1; + } + } + else { + *dst = NULL; + } + return 0; +} + + +static void _PyPathConfig_Clear(_PyPathConfig *config) { /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator, @@ -44,16 +60,11 @@ _PyPathConfig_Clear(_PyPathConfig *config) } -/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() - and Py_GetProgramFullPath() */ -_PyInitError -_PyPathConfig_Init(const _PyCoreConfig *core_config) +/* Calculate the path configuration: initialize path_config from core_config */ +static _PyInitError +_PyPathConfig_Calculate(_PyPathConfig *path_config, + const _PyCoreConfig *core_config) { - if (_Py_path_config.module_search_path) { - /* Already initialized */ - return _Py_INIT_OK(); - } - _PyInitError err; _PyPathConfig new_config = _PyPathConfig_INIT; @@ -62,31 +73,67 @@ _PyPathConfig_Init(const _PyCoreConfig *core_config) /* Calculate program_full_path, prefix, exec_prefix (Unix) or dll_path (Windows), and module_search_path */ - err = _PyPathConfig_Calculate(&new_config, core_config); + err = _PyPathConfig_Calculate_impl(&new_config, core_config); if (_Py_INIT_FAILED(err)) { - _PyPathConfig_Clear(&new_config); - goto done; + goto err; } /* Copy home and program_name from core_config */ - if (core_config->home != NULL) { - new_config.home = _PyMem_RawWcsdup(core_config->home); - if (new_config.home == NULL) { - err = _Py_INIT_NO_MEMORY(); - goto done; - } - } - else { - new_config.home = NULL; + if (copy_wstr(&new_config.home, core_config->home) < 0) { + err = _Py_INIT_NO_MEMORY(); + goto err; } - - new_config.program_name = _PyMem_RawWcsdup(core_config->program_name); - if (new_config.program_name == NULL) { + if (copy_wstr(&new_config.program_name, core_config->program_name) < 0) { err = _Py_INIT_NO_MEMORY(); - goto done; + goto err; } + _PyPathConfig_Clear(path_config); + *path_config = new_config; + + err = _Py_INIT_OK(); + goto done; + +err: + _PyPathConfig_Clear(&new_config); + +done: + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + return err; +} + + +_PyInitError +_PyPathConfig_SetGlobal(const _PyPathConfig *config) +{ + _PyInitError err; + _PyPathConfig new_config = _PyPathConfig_INIT; + + PyMemAllocatorEx old_alloc; + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + +#define COPY_ATTR(ATTR) \ + do { \ + if (copy_wstr(&new_config.ATTR, config->ATTR) < 0) { \ + _PyPathConfig_Clear(&new_config); \ + err = _Py_INIT_NO_MEMORY(); \ + goto done; \ + } \ + } while (0) + + COPY_ATTR(program_full_path); + COPY_ATTR(prefix); +#ifdef MS_WINDOWS + COPY_ATTR(dll_path); +#else + COPY_ATTR(exec_prefix); +#endif + COPY_ATTR(module_search_path); + COPY_ATTR(program_name); + COPY_ATTR(home); + _PyPathConfig_Clear(&_Py_path_config); + /* Steal new_config strings; don't clear new_config */ _Py_path_config = new_config; err = _Py_INIT_OK(); @@ -97,15 +144,228 @@ done: } +void +_PyPathConfig_ClearGlobal(void) +{ + _PyPathConfig_Clear(&_Py_path_config); +} + + +static wchar_t* +wstrlist_join(wchar_t sep, int count, wchar_t **list) +{ + size_t len = 1; /* NUL terminator */ + for (int i=0; i < count; i++) { + if (i != 0) { + len++; + } + len += wcslen(list[i]); + } + + wchar_t *text = PyMem_RawMalloc(len * sizeof(wchar_t)); + if (text == NULL) { + return NULL; + } + wchar_t *str = text; + for (int i=0; i < count; i++) { + wchar_t *path = list[i]; + if (i != 0) { + *str++ = SEP; + } + len = wcslen(path); + memcpy(str, path, len * sizeof(wchar_t)); + str += len; + } + *str = L'\0'; + + return text; +} + + +/* Set the global path configuration from core_config. */ +_PyInitError +_PyCoreConfig_SetPathConfig(const _PyCoreConfig *core_config) +{ + PyMemAllocatorEx old_alloc; + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + _PyInitError err; + _PyPathConfig path_config = _PyPathConfig_INIT; + + path_config.module_search_path = wstrlist_join(DELIM, + core_config->nmodule_search_path, + core_config->module_search_paths); + if (path_config.module_search_path == NULL) { + goto no_memory; + } + + if (copy_wstr(&path_config.program_full_path, core_config->executable) < 0) { + goto no_memory; + } + if (copy_wstr(&path_config.prefix, core_config->prefix) < 0) { + goto no_memory; + } +#ifdef MS_WINDOWS + if (copy_wstr(&path_config.dll_path, core_config->dll_path) < 0) { + goto no_memory; + } +#else + if (copy_wstr(&path_config.exec_prefix, core_config->exec_prefix) < 0) { + goto no_memory; + } +#endif + if (copy_wstr(&path_config.program_name, core_config->program_name) < 0) { + goto no_memory; + } + if (copy_wstr(&path_config.home, core_config->home) < 0) { + goto no_memory; + } + + err = _PyPathConfig_SetGlobal(&path_config); + if (_Py_INIT_FAILED(err)) { + goto done; + } + + err = _Py_INIT_OK(); + goto done; + +no_memory: + err = _Py_INIT_NO_MEMORY(); + +done: + _PyPathConfig_Clear(&path_config); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + return err; +} + + +static _PyInitError +core_config_init_module_search_paths(_PyCoreConfig *config, + _PyPathConfig *path_config) +{ + assert(config->module_search_paths == NULL); + assert(config->nmodule_search_path < 0); + + config->nmodule_search_path = 0; + + const wchar_t *sys_path = path_config->module_search_path; + const wchar_t delim = DELIM; + const wchar_t *p = sys_path; + while (1) { + p = wcschr(sys_path, delim); + if (p == NULL) { + p = sys_path + wcslen(sys_path); /* End of string */ + } + + size_t path_len = (p - sys_path); + wchar_t *path = PyMem_RawMalloc((path_len + 1) * sizeof(wchar_t)); + if (path == NULL) { + return _Py_INIT_NO_MEMORY(); + } + memcpy(path, sys_path, path_len * sizeof(wchar_t)); + path[path_len] = L'\0'; + + _PyInitError err = _Py_wstrlist_append(&config->nmodule_search_path, + &config->module_search_paths, + path); + PyMem_RawFree(path); + if (_Py_INIT_FAILED(err)) { + return err; + } + + if (*p == '\0') { + break; + } + sys_path = p + 1; + } + return _Py_INIT_OK(); +} + + +_PyInitError +_PyCoreConfig_InitPathConfig(_PyCoreConfig *config) +{ + _PyPathConfig path_config = _PyPathConfig_INIT; + _PyInitError err; + + err = _PyPathConfig_Calculate(&path_config, config); + if (_Py_INIT_FAILED(err)) { + goto error; + } + + if (config->nmodule_search_path < 0) { + err = core_config_init_module_search_paths(config, &path_config); + if (_Py_INIT_FAILED(err)) { + goto error; + } + } + + if (config->executable == NULL) { + if (copy_wstr(&config->executable, + path_config.program_full_path) < 0) { + goto no_memory; + } + } + + if (config->prefix == NULL) { + if (copy_wstr(&config->prefix, path_config.prefix) < 0) { + goto no_memory; + } + } + + if (config->exec_prefix == NULL) { +#ifdef MS_WINDOWS + wchar_t *exec_prefix = path_config.prefix; +#else + wchar_t *exec_prefix = path_config.exec_prefix; +#endif + if (copy_wstr(&config->exec_prefix, exec_prefix) < 0) { + goto no_memory; + } + } + +#ifdef MS_WINDOWS + if (config->dll_path == NULL) { + if (copy_wstr(&config->dll_path, path_config.dll_path) < 0) { + goto no_memory; + } + } +#endif + + if (config->base_prefix == NULL) { + if (copy_wstr(&config->base_prefix, config->prefix) < 0) { + goto no_memory; + } + } + + if (config->base_exec_prefix == NULL) { + if (copy_wstr(&config->base_exec_prefix, config->exec_prefix) < 0) { + goto no_memory; + } + } + + _PyPathConfig_Clear(&path_config); + return _Py_INIT_OK(); + +no_memory: + err = _Py_INIT_NO_MEMORY(); + +error: + _PyPathConfig_Clear(&path_config); + return err; +} + + static void pathconfig_global_init(void) { - if (_Py_path_config.module_search_path) { + if (_Py_path_config.module_search_path != NULL) { /* Already initialized */ return; } _PyInitError err; + _PyPathConfig path_config = _PyPathConfig_INIT; _PyCoreConfig config = _PyCoreConfig_INIT; err = _PyCoreConfig_Read(&config); @@ -113,15 +373,22 @@ pathconfig_global_init(void) goto error; } - err = _PyPathConfig_Init(&config); + err = _PyPathConfig_Calculate(&path_config, &config); if (_Py_INIT_FAILED(err)) { goto error; } + err = _PyPathConfig_SetGlobal(&path_config); + if (_Py_INIT_FAILED(err)) { + goto error; + } + + _PyPathConfig_Clear(&path_config); _PyCoreConfig_Clear(&config); return; error: + _PyPathConfig_Clear(&path_config); _PyCoreConfig_Clear(&config); _Py_FatalInitError(err); } @@ -142,13 +409,18 @@ Py_SetPath(const wchar_t *path) _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); #ifdef MS_WINDOWS new_config.dll_path = _PyMem_RawWcsdup(L""); + alloc_error |= (new_config.dll_path == NULL); #else new_config.exec_prefix = _PyMem_RawWcsdup(L""); + alloc_error |= (new_config.exec_prefix == NULL); #endif 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; @@ -160,6 +432,10 @@ Py_SetPath(const wchar_t *path) _Py_path_config = new_config; PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + if (alloc_error) { + Py_FatalError("Py_SetPath() failed: out of memory"); + } } |