From: Victor Stinner Date: Sat, 21 Sep 2019 00:13:14 +0000 (+0200) Subject: [3.8] bpo-38234: Fix PyConfig_Read() when Py_SetPath() was called (GH-16298) (GH... X-Git-Tag: v3.8.0rc1~60 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9f3dcf802eefeb5ab821ce3c7204ab46557d53d7;p=python [3.8] bpo-38234: Fix PyConfig_Read() when Py_SetPath() was called (GH-16298) (GH-16313) * bpo-38234: Remove _PyPathConfig.dll_path (GH-16307) The DLL path is not computed from any user configuration and cannot be configured by PyConfig. Instead, add a new _Py_dll_path global variable. Remove _PyConfig_SetPathConfig(): replaced with _PyPathConfig_Init(). Py_Initialize() now longer sets the "global path configuration", but only initialize _Py_dll_path. (cherry picked from commit c422167749f92d4170203e996a2c619c818335ea) * bpo-38234: Fix PyConfig_Read() when Py_SetPath() was called (GH-16298) * If Py_SetPath() has been called, _PyConfig_InitPathConfig() now uses its value. * Py_Initialize() now longer copies path configuration from PyConfig to the global path configuration (_Py_path_config). (cherry picked from commit e267793aa4101b2771ed0e66aaff5743d23f59af) --- diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index c0b3d95782..a7c1994eca 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -149,8 +149,6 @@ extern PyStatus _PyConfig_Copy( PyConfig *config, const PyConfig *config2); extern PyStatus _PyConfig_InitPathConfig(PyConfig *config); -extern PyStatus _PyConfig_SetPathConfig( - const PyConfig *config); extern void _PyConfig_Write(const PyConfig *config, _PyRuntimeState *runtime); extern PyStatus _PyConfig_SetPyArgv( diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h index 9e0ba0b01a..a2c488cdc2 100644 --- a/Include/internal/pycore_pathconfig.h +++ b/Include/internal/pycore_pathconfig.h @@ -13,10 +13,7 @@ typedef struct _PyPathConfig { wchar_t *program_full_path; wchar_t *prefix; wchar_t *exec_prefix; -#ifdef MS_WINDOWS - wchar_t *dll_path; -#endif - /* Set by Py_SetPath(), or computed by _PyPathConfig_Init() */ + /* Set by Py_SetPath(), or computed by _PyConfig_InitPathConfig() */ wchar_t *module_search_path; /* Python program name */ wchar_t *program_name; @@ -38,6 +35,9 @@ typedef struct _PyPathConfig { /* Note: _PyPathConfig_INIT sets other fields to 0/NULL */ PyAPI_DATA(_PyPathConfig) _Py_path_config; +#ifdef MS_WINDOWS +PyAPI_DATA(wchar_t*) _Py_dll_path; +#endif extern void _PyPathConfig_ClearGlobal(void); extern PyStatus _PyPathConfig_SetGlobal( @@ -59,6 +59,8 @@ extern int _Py_FindEnvConfigValue( extern wchar_t* _Py_GetDLLPath(void); #endif +extern PyStatus _PyPathConfig_Init(void); + #ifdef __cplusplus } #endif diff --git a/Misc/NEWS.d/next/C API/2019-09-20-17-22-41.bpo-38234.ZbquVK.rst b/Misc/NEWS.d/next/C API/2019-09-20-17-22-41.bpo-38234.ZbquVK.rst new file mode 100644 index 0000000000..6310f19f00 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-09-20-17-22-41.bpo-38234.ZbquVK.rst @@ -0,0 +1,2 @@ +Python ignored path passed to :c:func:`Py_SetPath`, fix Python +initialization to use the specified path. diff --git a/Modules/getpath.c b/Modules/getpath.c index dc0574851c..5afb5b1526 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -1213,10 +1213,12 @@ calculate_path_impl(const PyConfig *config, "Consider setting $PYTHONHOME to [:]\n"); } - status = calculate_module_search_path(config, calculate, - prefix, exec_prefix, pathconfig); - if (_PyStatus_EXCEPTION(status)) { - return status; + if (pathconfig->module_search_path == NULL) { + status = calculate_module_search_path(config, calculate, + prefix, exec_prefix, pathconfig); + if (_PyStatus_EXCEPTION(status)) { + return status; + } } status = calculate_reduce_prefix(calculate, prefix, Py_ARRAY_LENGTH(prefix)); diff --git a/PC/getpathp.c b/PC/getpathp.c index 7465d314b0..0ee53080bf 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -128,6 +128,8 @@ typedef struct { wchar_t argv0_path[MAXPATHLEN+1]; wchar_t zip_path[MAXPATHLEN+1]; + + wchar_t *dll_path; } PyCalculatePath; @@ -666,28 +668,36 @@ error: } -static void +static PyStatus calculate_init(PyCalculatePath *calculate, const PyConfig *config) { calculate->home = config->home; calculate->path_env = _wgetenv(L"PATH"); + + calculate->dll_path = _Py_GetDLLPath(); + if (calculate->dll_path == NULL) { + return _PyStatus_NO_MEMORY(); + } + + return _PyStatus_OK(); } static int -get_pth_filename(wchar_t *spbuffer, _PyPathConfig *pathconfig) +get_pth_filename(PyCalculatePath *calculate, wchar_t *filename, + const _PyPathConfig *pathconfig) { - if (pathconfig->dll_path[0]) { - if (!change_ext(spbuffer, pathconfig->dll_path, L"._pth") && - exists(spbuffer)) + if (calculate->dll_path[0]) { + if (!change_ext(filename, calculate->dll_path, L"._pth") && + exists(filename)) { return 1; } } if (pathconfig->program_full_path[0]) { - if (!change_ext(spbuffer, pathconfig->program_full_path, L"._pth") && - exists(spbuffer)) + if (!change_ext(filename, pathconfig->program_full_path, L"._pth") && + exists(filename)) { return 1; } @@ -697,15 +707,16 @@ get_pth_filename(wchar_t *spbuffer, _PyPathConfig *pathconfig) static int -calculate_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix) +calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig, + wchar_t *prefix) { - wchar_t spbuffer[MAXPATHLEN+1]; + wchar_t filename[MAXPATHLEN+1]; - if (!get_pth_filename(spbuffer, pathconfig)) { + if (!get_pth_filename(calculate, filename, pathconfig)) { return 0; } - return read_pth_file(pathconfig, prefix, spbuffer); + return read_pth_file(pathconfig, prefix, filename); } @@ -966,13 +977,6 @@ calculate_path_impl(const PyConfig *config, { PyStatus status; - assert(pathconfig->dll_path == NULL); - - pathconfig->dll_path = _Py_GetDLLPath(); - if (pathconfig->dll_path == NULL) { - return _PyStatus_NO_MEMORY(); - } - status = get_program_full_path(config, calculate, pathconfig); if (_PyStatus_EXCEPTION(status)) { return status; @@ -986,7 +990,7 @@ calculate_path_impl(const PyConfig *config, memset(prefix, 0, sizeof(prefix)); /* Search for a sys.path file */ - if (calculate_pth_file(pathconfig, prefix)) { + if (calculate_pth_file(calculate, pathconfig, prefix)) { goto done; } @@ -994,14 +998,17 @@ calculate_path_impl(const PyConfig *config, /* Calculate zip archive path from DLL or exe path */ change_ext(calculate->zip_path, - pathconfig->dll_path[0] ? pathconfig->dll_path : pathconfig->program_full_path, + calculate->dll_path[0] ? calculate->dll_path : pathconfig->program_full_path, L".zip"); calculate_home_prefix(calculate, prefix); - status = calculate_module_search_path(config, calculate, pathconfig, prefix); - if (_PyStatus_EXCEPTION(status)) { - return status; + if (pathconfig->module_search_path == NULL) { + status = calculate_module_search_path(config, calculate, + pathconfig, prefix); + if (_PyStatus_EXCEPTION(status)) { + return status; + } } done: @@ -1023,23 +1030,23 @@ calculate_free(PyCalculatePath *calculate) { PyMem_RawFree(calculate->machine_path); PyMem_RawFree(calculate->user_path); + PyMem_RawFree(calculate->dll_path); } PyStatus _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config) { + PyStatus status; PyCalculatePath calculate; memset(&calculate, 0, sizeof(calculate)); - calculate_init(&calculate, config); - - PyStatus status = calculate_path_impl(config, &calculate, pathconfig); + status = calculate_init(&calculate, config); if (_PyStatus_EXCEPTION(status)) { goto done; } - status = _PyStatus_OK(); + status = calculate_path_impl(config, &calculate, pathconfig); done: calculate_free(&calculate); @@ -1067,7 +1074,12 @@ _Py_CheckPython3(void) /* If there is a python3.dll next to the python3y.dll, assume this is a build tree; use that DLL */ - wcscpy(py3path, _Py_path_config.dll_path); + if (_Py_dll_path != NULL) { + wcscpy(py3path, _Py_dll_path); + } + else { + wcscpy(py3path, L""); + } s = wcsrchr(py3path, L'\\'); if (!s) { s = py3path; diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 79ec4af00d..1934f2e1c4 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -15,6 +15,9 @@ extern "C" { _PyPathConfig _Py_path_config = _PyPathConfig_INIT; +#ifdef MS_WINDOWS +wchar_t *_Py_dll_path = NULL; +#endif static int @@ -51,9 +54,6 @@ pathconfig_clear(_PyPathConfig *config) CLEAR(config->prefix); CLEAR(config->program_full_path); CLEAR(config->exec_prefix); -#ifdef MS_WINDOWS - CLEAR(config->dll_path); -#endif CLEAR(config->module_search_path); CLEAR(config->home); CLEAR(config->program_name); @@ -74,6 +74,13 @@ pathconfig_calculate(_PyPathConfig *pathconfig, const PyConfig *config) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + 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); @@ -114,47 +121,6 @@ done: } -PyStatus -_PyPathConfig_SetGlobal(const _PyPathConfig *config) -{ - PyStatus status; - _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) { \ - pathconfig_clear(&new_config); \ - status = _PyStatus_NO_MEMORY(); \ - goto done; \ - } \ - } while (0) - - COPY_ATTR(program_full_path); - COPY_ATTR(prefix); - COPY_ATTR(exec_prefix); -#ifdef MS_WINDOWS - COPY_ATTR(dll_path); -#endif - COPY_ATTR(module_search_path); - COPY_ATTR(program_name); - COPY_ATTR(home); - COPY_ATTR(base_executable); - - pathconfig_clear(&_Py_path_config); - /* Steal new_config strings; don't clear new_config */ - _Py_path_config = new_config; - - status = _PyStatus_OK(); - -done: - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - return status; -} - - void _PyPathConfig_ClearGlobal(void) { @@ -162,6 +128,10 @@ _PyPathConfig_ClearGlobal(void) _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); pathconfig_clear(&_Py_path_config); +#ifdef MS_WINDOWS + PyMem_RawFree(_Py_dll_path); + _Py_dll_path = NULL; +#endif PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } @@ -200,12 +170,36 @@ _PyWideStringList_Join(const PyWideStringList *list, wchar_t sep) /* Set the global path configuration from config. */ PyStatus -_PyConfig_SetPathConfig(const PyConfig *config) +_PyPathConfig_Init(void) { +#ifdef MS_WINDOWS + if (_Py_dll_path == NULL) { + /* Already set: nothing to do */ + return _PyStatus_OK(); + } + PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + _Py_dll_path = _Py_GetDLLPath(); + + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + if (_Py_dll_path == NULL) { + return _PyStatus_NO_MEMORY(); + } +#endif + return _PyStatus_OK(); +} + + +static PyStatus +pathconfig_global_init_from_config(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); @@ -222,12 +216,6 @@ _PyConfig_SetPathConfig(const PyConfig *config) if (copy_wstr(&pathconfig.exec_prefix, config->exec_prefix) < 0) { goto no_memory; } -#ifdef MS_WINDOWS - pathconfig.dll_path = _Py_GetDLLPath(); - if (pathconfig.dll_path == NULL) { - goto no_memory; - } -#endif if (copy_wstr(&pathconfig.program_name, config->program_name) < 0) { goto no_memory; } @@ -238,19 +226,18 @@ _PyConfig_SetPathConfig(const PyConfig *config) goto no_memory; } - status = _PyPathConfig_SetGlobal(&pathconfig); - if (_PyStatus_EXCEPTION(status)) { - goto done; - } + pathconfig_clear(&_Py_path_config); + /* Steal new_config strings; don't clear new_config */ + _Py_path_config = pathconfig; status = _PyStatus_OK(); goto done; no_memory: + pathconfig_clear(&pathconfig); status = _PyStatus_NO_MEMORY(); done: - pathconfig_clear(&pathconfig); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return status; } @@ -402,12 +389,17 @@ _PyConfig_InitPathConfig(PyConfig *config) static void pathconfig_global_init(void) { + /* 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); @@ -416,7 +408,7 @@ pathconfig_global_init(void) goto error; } - status = _PyConfig_SetPathConfig(&config); + status = pathconfig_global_init_from_config(&config); if (_PyStatus_EXCEPTION(status)) { goto error; } @@ -450,10 +442,6 @@ Py_SetPath(const wchar_t *path) alloc_error |= (new_config.prefix == NULL); new_config.exec_prefix = _PyMem_RawWcsdup(L""); alloc_error |= (new_config.exec_prefix == NULL); -#ifdef MS_WINDOWS - new_config.dll_path = _Py_GetDLLPath(); - alloc_error |= (new_config.dll_path == NULL); -#endif new_config.module_search_path = _PyMem_RawWcsdup(path); alloc_error |= (new_config.module_search_path == NULL); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 97bb99256d..a9a6589d7a 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -472,7 +472,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime, config = &interp->config; if (config->_install_importlib) { - status = _PyConfig_SetPathConfig(config); + status = _PyPathConfig_Init(); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -623,6 +623,8 @@ pycore_init_builtins(PyInterpreterState *interp) static PyStatus pycore_init_import_warnings(PyInterpreterState *interp, PyObject *sysmod) { + const PyConfig *config = &interp->config; + PyStatus status = _PyImport_Init(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -638,15 +640,15 @@ pycore_init_import_warnings(PyInterpreterState *interp, PyObject *sysmod) return _PyStatus_ERR("can't initialize warnings"); } - if (interp->config._install_importlib) { - status = _PyConfig_SetPathConfig(&interp->config); + if (config->_install_importlib) { + status = _PyPathConfig_Init(); if (_PyStatus_EXCEPTION(status)) { return status; } } /* This call sets up builtin and frozen import support */ - if (interp->config._install_importlib) { + if (config->_install_importlib) { status = init_importlib(interp, sysmod); if (_PyStatus_EXCEPTION(status)) { return status;