[Python-checkins] bpo-34170: Rework _PyCoreConfig_Read() to avoid side effect (GH-8353)

Victor Stinner webhook-mailer at python.org
Fri Jul 20 20:06:21 EDT 2018


https://github.com/python/cpython/commit/b1147e43daeb3c51a63056b489e8d868404d4e22
commit: b1147e43daeb3c51a63056b489e8d868404d4e22
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2018-07-21T02:06:16+02:00
summary:

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.

files:
M Include/internal/pystate.h
M Include/pylifecycle.h
M Include/pystate.h
M Modules/getpath.c
M Modules/main.c
M PC/getpathp.c
M Python/pathconfig.c
M Python/pylifecycle.c

diff --git a/Include/internal/pystate.h b/Include/internal/pystate.h
index 70e066662582..83fa7dc33cf6 100644
--- a/Include/internal/pystate.h
+++ b/Include/internal/pystate.h
@@ -37,7 +37,7 @@ struct _gilstate_runtime_state {
 #define _PyGILState_check_enabled _PyRuntime.gilstate.check_enabled
 
 
-typedef struct {
+typedef struct _PyPathConfig {
     /* Full path to the Python program */
     wchar_t *program_full_path;
     wchar_t *prefix;
@@ -59,11 +59,15 @@ typedef struct {
 
 PyAPI_DATA(_PyPathConfig) _Py_path_config;
 
-PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate(
+PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl(
     _PyPathConfig *config,
     const _PyCoreConfig *core_config);
-PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config);
+PyAPI_FUNC(void) _PyPathConfig_ClearGlobal(void);
 
+PyAPI_FUNC(_PyInitError) _Py_wstrlist_append(
+    int *len,
+    wchar_t ***list,
+    const wchar_t *str);
 
 /* interpreter state */
 
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h
index 95dd55b05173..9644116ba62c 100644
--- a/Include/pylifecycle.h
+++ b/Include/pylifecycle.h
@@ -59,6 +59,9 @@ PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
 PyAPI_FUNC(int) _PyCoreConfig_Copy(
     _PyCoreConfig *config,
     const _PyCoreConfig *config2);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPathConfig(_PyCoreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetPathConfig(
+    const _PyCoreConfig *config);
 
 PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read(
     _PyMainInterpreterConfig *config,
@@ -116,7 +119,11 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
 PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
 PyAPI_FUNC(wchar_t *) Py_GetPath(void);
 #ifdef Py_BUILD_CORE
-PyAPI_FUNC(_PyInitError) _PyPathConfig_Init(const _PyCoreConfig *core_config);
+struct _PyPathConfig;
+typedef struct _PyPathConfig _PyPathConfig;
+
+PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal(
+    const _PyPathConfig *config);
 PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv);
 PyAPI_FUNC(int) _Py_FindEnvConfigValue(
     FILE *env_file,
diff --git a/Include/pystate.h b/Include/pystate.h
index 8158cabc7171..ac09dc309271 100644
--- a/Include/pystate.h
+++ b/Include/pystate.h
@@ -71,6 +71,9 @@ typedef struct {
     wchar_t *base_prefix;   /* sys.base_prefix */
     wchar_t *exec_prefix;   /* sys.exec_prefix */
     wchar_t *base_exec_prefix;  /* sys.base_exec_prefix */
+#ifdef MS_WINDOWS
+    wchar_t *dll_path;      /* Windows DLL path */
+#endif
 
     /* Private fields */
     int _disable_importlib; /* Needed by freeze_importlib */
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 755298eb4b78..6d966e1bced4 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -946,7 +946,7 @@ calculate_path_impl(const _PyCoreConfig *core_config,
 
 
 _PyInitError
-_PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
+_PyPathConfig_Calculate_impl(_PyPathConfig *config, const _PyCoreConfig *core_config)
 {
     PyCalculatePath calculate;
     memset(&calculate, 0, sizeof(calculate));
diff --git a/Modules/main.c b/Modules/main.c
index 1ff985517db7..5166e7429208 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -650,7 +650,7 @@ pymain_free_raw(_PyMain *pymain)
        configuration options set before Py_Initialize() which should
        remain valid after Py_Finalize(), since
        Py_Initialize()-Py_Finalize() can be called multiple times. */
-    _PyPathConfig_Clear(&_Py_path_config);
+    _PyPathConfig_ClearGlobal();
 
     pymain_clear_config(pymain);
 
@@ -701,9 +701,13 @@ pymain_run_main_from_importer(_PyMain *pymain)
 }
 
 
-static _PyInitError
-wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
+_PyInitError
+_Py_wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
 {
+    if (*len == INT_MAX) {
+        /* len+1 would overflow */
+        return _Py_INIT_NO_MEMORY();
+    }
     wchar_t *str2 = _PyMem_RawWcsdup(str);
     if (str2 == NULL) {
         return _Py_INIT_NO_MEMORY();
@@ -725,7 +729,7 @@ wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
 static int
 pymain_wstrlist_append(_PyMain *pymain, int *len, wchar_t ***list, const wchar_t *str)
 {
-    _PyInitError err = wstrlist_append(len, list, str);
+    _PyInitError err = _Py_wstrlist_append(len, list, str);
     if (_Py_INIT_FAILED(err)) {
         pymain->err = err;
         return -1;
@@ -972,9 +976,9 @@ static _PyInitError
 config_add_warnings_optlist(_PyCoreConfig *config, int len, wchar_t **options)
 {
     for (int i = 0; i < len; i++) {
-        _PyInitError err = wstrlist_append(&config->nwarnoption,
-                                           &config->warnoptions,
-                                           options[i]);
+        _PyInitError err = _Py_wstrlist_append(&config->nwarnoption,
+                                               &config->warnoptions,
+                                               options[i]);
         if (_Py_INIT_FAILED(err)) {
             return err;
         }
@@ -1006,9 +1010,9 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline)
      */
 
     if (config->dev_mode) {
-        err = wstrlist_append(&config->nwarnoption,
-                              &config->warnoptions,
-                              L"default");
+        err = _Py_wstrlist_append(&config->nwarnoption,
+                                  &config->warnoptions,
+                                  L"default");
         if (_Py_INIT_FAILED(err)) {
             return err;
         }
@@ -1040,9 +1044,9 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline)
         else {
             filter = L"default::BytesWarning";
         }
-        err = wstrlist_append(&config->nwarnoption,
-                              &config->warnoptions,
-                              filter);
+        err = _Py_wstrlist_append(&config->nwarnoption,
+                                  &config->warnoptions,
+                                  filter);
         if (_Py_INIT_FAILED(err)) {
             return err;
         }
@@ -1077,9 +1081,9 @@ cmdline_init_env_warnoptions(_Py_CommandLineDetails *cmdline)
          warning != NULL;
          warning = WCSTOK(NULL, L",", &context))
     {
-        _PyInitError err = wstrlist_append(&cmdline->nenv_warnoption,
-                                           &cmdline->env_warnoptions,
-                                          warning);
+        _PyInitError err = _Py_wstrlist_append(&cmdline->nenv_warnoption,
+                                               &cmdline->env_warnoptions,
+                                               warning);
         if (_Py_INIT_FAILED(err)) {
             PyMem_RawFree(env);
             return err;
@@ -2099,101 +2103,6 @@ config_init_locale(_PyCoreConfig *config)
 }
 
 
-static _PyInitError
-config_init_module_search_paths(_PyCoreConfig *config)
-{
-    assert(config->module_search_paths == NULL);
-    assert(config->nmodule_search_path < 0);
-
-    config->nmodule_search_path = 0;
-
-    const wchar_t *sys_path = Py_GetPath();
-    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 = 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();
-}
-
-
-static _PyInitError
-config_init_path_config(_PyCoreConfig *config)
-{
-    _PyInitError err = _PyPathConfig_Init(config);
-    if (_Py_INIT_FAILED(err)) {
-        return err;
-    }
-
-    if (config->nmodule_search_path < 0) {
-        err = config_init_module_search_paths(config);
-        if (_Py_INIT_FAILED(err)) {
-            return err;
-        }
-    }
-
-    if (config->executable == NULL) {
-        config->executable = _PyMem_RawWcsdup(Py_GetProgramFullPath());
-        if (config->executable == NULL) {
-            return _Py_INIT_NO_MEMORY();
-        }
-    }
-
-    if (config->prefix == NULL) {
-        config->prefix = _PyMem_RawWcsdup(Py_GetPrefix());
-        if (config->prefix == NULL) {
-            return _Py_INIT_NO_MEMORY();
-        }
-    }
-
-    if (config->exec_prefix == NULL) {
-        config->exec_prefix = _PyMem_RawWcsdup(Py_GetExecPrefix());
-        if (config->exec_prefix == NULL) {
-            return _Py_INIT_NO_MEMORY();
-        }
-    }
-
-    if (config->base_prefix == NULL) {
-        config->base_prefix = _PyMem_RawWcsdup(config->prefix);
-        if (config->base_prefix == NULL) {
-            return _Py_INIT_NO_MEMORY();
-        }
-    }
-
-    if (config->base_exec_prefix == NULL) {
-        config->base_exec_prefix = _PyMem_RawWcsdup(config->exec_prefix);
-        if (config->base_exec_prefix == NULL) {
-            return _Py_INIT_NO_MEMORY();
-        }
-    }
-
-    return _Py_INIT_OK();
-}
-
 /* Read configuration settings from standard locations
  *
  * This function doesn't make any changes to the interpreter state - it
@@ -2252,7 +2161,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
     }
 
     if (!config->_disable_importlib) {
-        err = config_init_path_config(config);
+        err = _PyCoreConfig_InitPathConfig(config);
         if (_Py_INIT_FAILED(err)) {
             return err;
         }
@@ -2294,6 +2203,9 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
     CLEAR(config->prefix);
     CLEAR(config->base_prefix);
     CLEAR(config->exec_prefix);
+#ifdef MS_WINDOWS
+    CLEAR(config->dll_path);
+#endif
     CLEAR(config->base_exec_prefix);
 #undef CLEAR
 #undef CLEAR_WSTRLIST
@@ -2356,6 +2268,9 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
     COPY_STR_ATTR(prefix);
     COPY_STR_ATTR(base_prefix);
     COPY_STR_ATTR(exec_prefix);
+#ifdef MS_WINDOWS
+    COPY_STR_ATTR(dll_path);
+#endif
     COPY_STR_ATTR(base_exec_prefix);
 
 #undef COPY_ATTR
diff --git a/PC/getpathp.c b/PC/getpathp.c
index 93828432ae3c..fa687b7056b2 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -1000,7 +1000,7 @@ calculate_free(PyCalculatePath *calculate)
 
 
 _PyInitError
-_PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
+_PyPathConfig_Calculate_impl(_PyPathConfig *config, const _PyCoreConfig *core_config)
 {
     PyCalculatePath calculate;
     memset(&calculate, 0, sizeof(calculate));
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index 07aa01c0304f..e987df1b1fdf 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 @@ _PyPathConfig_Init(const _PyCoreConfig *core_config)
 }
 
 
+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");
+    }
 }
 
 
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 64fa1e58f7d7..325f42305f39 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -759,6 +759,13 @@ _Py_InitializeCore(const _PyCoreConfig *core_config)
     if (!_PyContext_Init())
         return _Py_INIT_ERR("can't init context");
 
+    if (!core_config->_disable_importlib) {
+        err = _PyCoreConfig_SetPathConfig(core_config);
+        if (_Py_INIT_FAILED(err)) {
+            return err;
+        }
+    }
+
     /* This call sets up builtin and frozen import support */
     if (!interp->core_config._disable_importlib) {
         err = initimport(interp, sysmod);



More information about the Python-checkins mailing list