[Python-checkins] [3.8] bpo-38234: Fix PyConfig_Read() when Py_SetPath() was called (GH-16298) (GH-16313)

Victor Stinner webhook-mailer at python.org
Fri Sep 20 20:13:18 EDT 2019


https://github.com/python/cpython/commit/9f3dcf802eefeb5ab821ce3c7204ab46557d53d7
commit: 9f3dcf802eefeb5ab821ce3c7204ab46557d53d7
branch: 3.8
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2019-09-21T02:13:14+02:00
summary:

[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)

files:
A Misc/NEWS.d/next/C API/2019-09-20-17-22-41.bpo-38234.ZbquVK.rst
M Include/internal/pycore_initconfig.h
M Include/internal/pycore_pathconfig.h
M Modules/getpath.c
M PC/getpathp.c
M Python/pathconfig.c
M Python/pylifecycle.c

diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h
index c0b3d957827a..a7c1994eca16 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 9e0ba0b01a80..a2c488cdc2eb 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 000000000000..6310f19f004e
--- /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 dc0574851c3b..5afb5b152638 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -1213,10 +1213,12 @@ calculate_path_impl(const PyConfig *config,
                 "Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\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 7465d314b043..0ee53080bf31 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 @@ read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path)
 }
 
 
-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 79ec4af00d83..1934f2e1c4b8 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 @@ pathconfig_calculate(_PyPathConfig *pathconfig, const PyConfig *config)
 }
 
 
-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 97bb99256d89..a9a6589d7a43 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;



More information about the Python-checkins mailing list