[Python-checkins] bpo-32030: Add _PyPathConfig_Init() (#4551)

Victor Stinner webhook-mailer at python.org
Fri Nov 24 21:17:59 EST 2017


https://github.com/python/cpython/commit/9316ee4da2dcc217351418fc4dbe9205995689e0
commit: 9316ee4da2dcc217351418fc4dbe9205995689e0
branch: master
author: Victor Stinner <victor.stinner at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-11-25T03:17:57+01:00
summary:

bpo-32030: Add _PyPathConfig_Init() (#4551)

* Add _PyPathConfig_Init() and _PyPathConfig_Fini()
* Remove _Py_GetPathWithConfig()
* _PyPathConfig_Init() returns _PyInitError to allow to handle errors
  properly
* Add pathconfig_clear()
* Windows calculate_path_impl(): replace Py_FatalError() with
  _PyInitError
* Py_FinalizeEx() now calls _PyPathConfig_Fini() to release memory
* Fix _Py_InitializeMainInterpreter() regression: don't initialize
  path config if _disable_importlib is false
* PyPathConfig now uses dynamically allocated memory

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

diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h
index ff915323386..d32c98b6985 100644
--- a/Include/pylifecycle.h
+++ b/Include/pylifecycle.h
@@ -103,8 +103,9 @@ 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(wchar_t *) _Py_GetPathWithConfig(
-    const _PyMainInterpreterConfig *config);
+PyAPI_FUNC(_PyInitError) _PyPathConfig_Init(
+    const _PyMainInterpreterConfig *main_config);
+PyAPI_FUNC(void) _PyPathConfig_Fini(void);
 #endif
 PyAPI_FUNC(void)      Py_SetPath(const wchar_t *);
 #ifdef MS_WINDOWS
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 9078aa81b32..02d626cea73 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -109,10 +109,16 @@ extern "C" {
 #define LANDMARK L"os.py"
 #endif
 
+#define DECODE_LOCALE_ERR(NAME, LEN) \
+    ((LEN) == (size_t)-2) \
+     ? _Py_INIT_USER_ERR("cannot decode " #NAME) \
+     : _Py_INIT_NO_MEMORY()
+
+
 typedef struct {
-    wchar_t prefix[MAXPATHLEN+1];
-    wchar_t exec_prefix[MAXPATHLEN+1];
-    wchar_t program_name[MAXPATHLEN+1];
+    wchar_t *prefix;
+    wchar_t *exec_prefix;
+    wchar_t *program_name;
     wchar_t *module_search_path;
 } PyPathConfig;
 
@@ -361,63 +367,63 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
    bytes long.
 */
 static int
-search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config)
+search_for_prefix(PyCalculatePath *calculate, wchar_t *prefix)
 {
     size_t n;
     wchar_t *vpath;
 
     /* If PYTHONHOME is set, we believe it unconditionally */
     if (calculate->home) {
-        wcsncpy(config->prefix, calculate->home, MAXPATHLEN);
-        config->prefix[MAXPATHLEN] = L'\0';
-        wchar_t *delim = wcschr(config->prefix, DELIM);
+        wcsncpy(prefix, calculate->home, MAXPATHLEN);
+        prefix[MAXPATHLEN] = L'\0';
+        wchar_t *delim = wcschr(prefix, DELIM);
         if (delim) {
             *delim = L'\0';
         }
-        joinpath(config->prefix, calculate->lib_python);
-        joinpath(config->prefix, LANDMARK);
+        joinpath(prefix, calculate->lib_python);
+        joinpath(prefix, LANDMARK);
         return 1;
     }
 
     /* Check to see if argv[0] is in the build directory */
-    wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN);
-    config->prefix[MAXPATHLEN] = L'\0';
-    joinpath(config->prefix, L"Modules/Setup");
-    if (isfile(config->prefix)) {
+    wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN);
+    prefix[MAXPATHLEN] = L'\0';
+    joinpath(prefix, L"Modules/Setup");
+    if (isfile(prefix)) {
         /* Check VPATH to see if argv0_path is in the build directory. */
         vpath = Py_DecodeLocale(VPATH, NULL);
         if (vpath != NULL) {
-            wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN);
-            config->prefix[MAXPATHLEN] = L'\0';
-            joinpath(config->prefix, vpath);
+            wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN);
+            prefix[MAXPATHLEN] = L'\0';
+            joinpath(prefix, vpath);
             PyMem_RawFree(vpath);
-            joinpath(config->prefix, L"Lib");
-            joinpath(config->prefix, LANDMARK);
-            if (ismodule(config->prefix)) {
+            joinpath(prefix, L"Lib");
+            joinpath(prefix, LANDMARK);
+            if (ismodule(prefix)) {
                 return -1;
             }
         }
     }
 
     /* Search from argv0_path, until root is found */
-    copy_absolute(config->prefix, calculate->argv0_path, MAXPATHLEN+1);
+    copy_absolute(prefix, calculate->argv0_path, MAXPATHLEN+1);
     do {
-        n = wcslen(config->prefix);
-        joinpath(config->prefix, calculate->lib_python);
-        joinpath(config->prefix, LANDMARK);
-        if (ismodule(config->prefix)) {
+        n = wcslen(prefix);
+        joinpath(prefix, calculate->lib_python);
+        joinpath(prefix, LANDMARK);
+        if (ismodule(prefix)) {
             return 1;
         }
-        config->prefix[n] = L'\0';
-        reduce(config->prefix);
-    } while (config->prefix[0]);
+        prefix[n] = L'\0';
+        reduce(prefix);
+    } while (prefix[0]);
 
     /* Look at configure's PREFIX */
-    wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
-    config->prefix[MAXPATHLEN] = L'\0';
-    joinpath(config->prefix, calculate->lib_python);
-    joinpath(config->prefix, LANDMARK);
-    if (ismodule(config->prefix)) {
+    wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
+    prefix[MAXPATHLEN] = L'\0';
+    joinpath(prefix, calculate->lib_python);
+    joinpath(prefix, LANDMARK);
+    if (ismodule(prefix)) {
         return 1;
     }
 
@@ -427,25 +433,25 @@ search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config)
 
 
 static void
-calculate_prefix(PyCalculatePath *calculate, PyPathConfig *config)
+calculate_prefix(PyCalculatePath *calculate, wchar_t *prefix)
 {
-    calculate->prefix_found = search_for_prefix(calculate, config);
+    calculate->prefix_found = search_for_prefix(calculate, prefix);
     if (!calculate->prefix_found) {
         if (!Py_FrozenFlag) {
             fprintf(stderr,
                 "Could not find platform independent libraries <prefix>\n");
         }
-        wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
-        joinpath(config->prefix, calculate->lib_python);
+        wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
+        joinpath(prefix, calculate->lib_python);
     }
     else {
-        reduce(config->prefix);
+        reduce(prefix);
     }
 }
 
 
 static void
-calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config)
+calculate_reduce_prefix(PyCalculatePath *calculate, wchar_t *prefix)
 {
     /* Reduce prefix and exec_prefix to their essence,
      * e.g. /usr/local/lib/python1.5 is reduced to /usr/local.
@@ -453,16 +459,16 @@ calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config)
      * return the compiled-in defaults instead.
      */
     if (calculate->prefix_found > 0) {
-        reduce(config->prefix);
-        reduce(config->prefix);
+        reduce(prefix);
+        reduce(prefix);
         /* The prefix is the root directory, but reduce() chopped
          * off the "/". */
-        if (!config->prefix[0]) {
-            wcscpy(config->prefix, separator);
+        if (!prefix[0]) {
+            wcscpy(prefix, separator);
         }
     }
     else {
-        wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
+        wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
     }
 }
 
@@ -471,7 +477,7 @@ calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config)
    MAXPATHLEN bytes long.
 */
 static int
-search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
+search_for_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
 {
     size_t n;
 
@@ -479,25 +485,25 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
     if (calculate->home) {
         wchar_t *delim = wcschr(calculate->home, DELIM);
         if (delim) {
-            wcsncpy(config->exec_prefix, delim+1, MAXPATHLEN);
+            wcsncpy(exec_prefix, delim+1, MAXPATHLEN);
         }
         else {
-            wcsncpy(config->exec_prefix, calculate->home, MAXPATHLEN);
+            wcsncpy(exec_prefix, calculate->home, MAXPATHLEN);
         }
-        config->exec_prefix[MAXPATHLEN] = L'\0';
-        joinpath(config->exec_prefix, calculate->lib_python);
-        joinpath(config->exec_prefix, L"lib-dynload");
+        exec_prefix[MAXPATHLEN] = L'\0';
+        joinpath(exec_prefix, calculate->lib_python);
+        joinpath(exec_prefix, L"lib-dynload");
         return 1;
     }
 
     /* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
        is written by setup.py and contains the relative path to the location
        of shared library modules. */
-    wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN);
-    config->exec_prefix[MAXPATHLEN] = L'\0';
-    joinpath(config->exec_prefix, L"pybuilddir.txt");
-    if (isfile(config->exec_prefix)) {
-        FILE *f = _Py_wfopen(config->exec_prefix, L"rb");
+    wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN);
+    exec_prefix[MAXPATHLEN] = L'\0';
+    joinpath(exec_prefix, L"pybuilddir.txt");
+    if (isfile(exec_prefix)) {
+        FILE *f = _Py_wfopen(exec_prefix, L"rb");
         if (f == NULL) {
             errno = 0;
         }
@@ -516,9 +522,9 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
                 Py_DECREF(decoded);
                 if (k >= 0) {
                     rel_builddir_path[k] = L'\0';
-                    wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN);
-                    config->exec_prefix[MAXPATHLEN] = L'\0';
-                    joinpath(config->exec_prefix, rel_builddir_path);
+                    wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN);
+                    exec_prefix[MAXPATHLEN] = L'\0';
+                    joinpath(exec_prefix, rel_builddir_path);
                     return -1;
                 }
             }
@@ -526,24 +532,24 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
     }
 
     /* Search from argv0_path, until root is found */
-    copy_absolute(config->exec_prefix, calculate->argv0_path, MAXPATHLEN+1);
+    copy_absolute(exec_prefix, calculate->argv0_path, MAXPATHLEN+1);
     do {
-        n = wcslen(config->exec_prefix);
-        joinpath(config->exec_prefix, calculate->lib_python);
-        joinpath(config->exec_prefix, L"lib-dynload");
-        if (isdir(config->exec_prefix)) {
+        n = wcslen(exec_prefix);
+        joinpath(exec_prefix, calculate->lib_python);
+        joinpath(exec_prefix, L"lib-dynload");
+        if (isdir(exec_prefix)) {
             return 1;
         }
-        config->exec_prefix[n] = L'\0';
-        reduce(config->exec_prefix);
-    } while (config->exec_prefix[0]);
+        exec_prefix[n] = L'\0';
+        reduce(exec_prefix);
+    } while (exec_prefix[0]);
 
     /* Look at configure's EXEC_PREFIX */
-    wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
-    config->exec_prefix[MAXPATHLEN] = L'\0';
-    joinpath(config->exec_prefix, calculate->lib_python);
-    joinpath(config->exec_prefix, L"lib-dynload");
-    if (isdir(config->exec_prefix)) {
+    wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
+    exec_prefix[MAXPATHLEN] = L'\0';
+    joinpath(exec_prefix, calculate->lib_python);
+    joinpath(exec_prefix, L"lib-dynload");
+    if (isdir(exec_prefix)) {
         return 1;
     }
 
@@ -553,41 +559,44 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
 
 
 static void
-calculate_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
+calculate_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
 {
-    calculate->exec_prefix_found = search_for_exec_prefix(calculate, config);
+    calculate->exec_prefix_found = search_for_exec_prefix(calculate, exec_prefix);
     if (!calculate->exec_prefix_found) {
         if (!Py_FrozenFlag) {
             fprintf(stderr,
                 "Could not find platform dependent libraries <exec_prefix>\n");
         }
-        wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
-        joinpath(config->exec_prefix, L"lib/lib-dynload");
+        wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
+        joinpath(exec_prefix, L"lib/lib-dynload");
     }
     /* If we found EXEC_PREFIX do *not* reduce it!  (Yet.) */
 }
 
 
 static void
-calculate_reduce_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
+calculate_reduce_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
 {
     if (calculate->exec_prefix_found > 0) {
-        reduce(config->exec_prefix);
-        reduce(config->exec_prefix);
-        reduce(config->exec_prefix);
-        if (!config->exec_prefix[0]) {
-            wcscpy(config->exec_prefix, separator);
+        reduce(exec_prefix);
+        reduce(exec_prefix);
+        reduce(exec_prefix);
+        if (!exec_prefix[0]) {
+            wcscpy(exec_prefix, separator);
         }
     }
     else {
-        wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
+        wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
     }
 }
 
 
-static void
-calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
+static _PyInitError
+calculate_program_name(PyCalculatePath *calculate, PyPathConfig *config)
 {
+    wchar_t program_name[MAXPATHLEN+1];
+    memset(program_name, 0, sizeof(program_name));
+
 #ifdef __APPLE__
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
     uint32_t nsexeclength = MAXPATHLEN;
@@ -603,7 +612,7 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
      * $PATH isn't exported, you lose.
      */
     if (wcschr(calculate->program_name, SEP)) {
-        wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN);
+        wcsncpy(program_name, calculate->program_name, MAXPATHLEN);
     }
 #ifdef __APPLE__
      /* On Mac OS X, if a script uses an interpreter of the form
@@ -619,10 +628,10 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
     else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) &&
             execpath[0] == SEP)
     {
-        size_t r = mbstowcs(config->program_name, execpath, MAXPATHLEN+1);
+        size_t r = mbstowcs(program_name, execpath, MAXPATHLEN+1);
         if (r == (size_t)-1 || r > MAXPATHLEN) {
             /* Could not convert execpath, or it's too long. */
-            config->program_name[0] = '\0';
+            program_name[0] = '\0';
         }
     }
 #endif /* __APPLE__ */
@@ -636,38 +645,44 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
                 if (len > MAXPATHLEN) {
                     len = MAXPATHLEN;
                 }
-                wcsncpy(config->program_name, path, len);
-                *(config->program_name + len) = '\0';
+                wcsncpy(program_name, path, len);
+                program_name[len] = '\0';
             }
             else {
-                wcsncpy(config->program_name, path, MAXPATHLEN);
+                wcsncpy(program_name, path, MAXPATHLEN);
             }
 
-            joinpath(config->program_name, calculate->program_name);
-            if (isxfile(config->program_name)) {
+            joinpath(program_name, calculate->program_name);
+            if (isxfile(program_name)) {
                 break;
             }
 
             if (!delim) {
-                config->program_name[0] = L'\0';
+                program_name[0] = L'\0';
                 break;
             }
             path = delim + 1;
         }
     }
     else {
-        config->program_name[0] = '\0';
+        program_name[0] = '\0';
+    }
+    if (program_name[0] != SEP && program_name[0] != '\0') {
+        absolutize(program_name);
     }
-    if (config->program_name[0] != SEP && config->program_name[0] != '\0') {
-        absolutize(config->program_name);
+
+    config->program_name = _PyMem_RawWcsdup(program_name);
+    if (config->program_name == NULL) {
+        return _Py_INIT_NO_MEMORY();
     }
+    return _Py_INIT_OK();
 }
 
 
-static void
-calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
+static _PyInitError
+calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_name)
 {
-    wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN);
+    wcsncpy(calculate->argv0_path, program_name, MAXPATHLEN);
     calculate->argv0_path[MAXPATHLEN] = '\0';
 
 #ifdef WITH_NEXT_FRAMEWORK
@@ -690,9 +705,10 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
         ** be running the interpreter in the build directory, so we use the
         ** build-directory-specific logic to find Lib and such.
         */
-        wchar_t* wbuf = Py_DecodeLocale(modPath, NULL);
+        size_t len;
+        wchar_t* wbuf = Py_DecodeLocale(modPath, &len);
         if (wbuf == NULL) {
-            Py_FatalError("Cannot decode framework location");
+            return DECODE_LOCALE_ERR("framework location", len);
         }
 
         wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
@@ -702,7 +718,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
         if (!ismodule(calculate->argv0_path)) {
             /* We are in the build directory so use the name of the
                executable - we know that the absolute path is passed */
-            wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN);
+            wcsncpy(calculate->argv0_path, program_name, MAXPATHLEN);
         }
         else {
             /* Use the location of the library as the program_name */
@@ -714,7 +730,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
 
 #if HAVE_READLINK
     wchar_t tmpbuffer[MAXPATHLEN+1];
-    int linklen = _Py_wreadlink(config->program_name, tmpbuffer, MAXPATHLEN);
+    int linklen = _Py_wreadlink(program_name, tmpbuffer, MAXPATHLEN);
     while (linklen != -1) {
         if (tmpbuffer[0] == SEP) {
             /* tmpbuffer should never be longer than MAXPATHLEN,
@@ -733,6 +749,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
     reduce(calculate->argv0_path);
     /* At this point, argv0_path is guaranteed to be less than
        MAXPATHLEN bytes long. */
+    return _Py_INIT_OK();
 }
 
 
@@ -777,9 +794,9 @@ calculate_read_pyenv(PyCalculatePath *calculate)
 
 
 static void
-calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config)
+calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix)
 {
-    wcsncpy(calculate->zip_path, config->prefix, MAXPATHLEN);
+    wcsncpy(calculate->zip_path, prefix, MAXPATHLEN);
     calculate->zip_path[MAXPATHLEN] = L'\0';
 
     if (calculate->prefix_found > 0) {
@@ -799,8 +816,10 @@ calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config)
 }
 
 
-static wchar_t *
-calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
+static _PyInitError
+calculate_module_search_path(PyCalculatePath *calculate,
+                             const wchar_t *prefix, const wchar_t *exec_prefix,
+                             PyPathConfig *config)
 {
     /* Calculate size of return buffer */
     size_t bufsz = 0;
@@ -809,7 +828,7 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
     }
 
     wchar_t *defpath = calculate->pythonpath;
-    size_t prefixsz = wcslen(config->prefix) + 1;
+    size_t prefixsz = wcslen(prefix) + 1;
     while (1) {
         wchar_t *delim = wcschr(defpath, DELIM);
 
@@ -829,13 +848,12 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
     }
 
     bufsz += wcslen(calculate->zip_path) + 1;
-    bufsz += wcslen(config->exec_prefix) + 1;
+    bufsz += wcslen(exec_prefix) + 1;
 
     /* Allocate the buffer */
     wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
     if (buf == NULL) {
-        Py_FatalError(
-            "Not enough memory for dynamic PYTHONPATH");
+        return _Py_INIT_NO_MEMORY();
     }
     buf[0] = '\0';
 
@@ -857,8 +875,8 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
         wchar_t *delim = wcschr(defpath, DELIM);
 
         if (defpath[0] != SEP) {
-            wcscat(buf, config->prefix);
-            if (prefixsz >= 2 && config->prefix[prefixsz - 2] != SEP &&
+            wcscat(buf, prefix);
+            if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP &&
                 defpath[0] != (delim ? DELIM : L'\0'))
             {
                 /* not empty */
@@ -870,7 +888,7 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
             size_t len = delim - defpath + 1;
             size_t end = wcslen(buf) + len;
             wcsncat(buf, defpath, len);
-            *(buf + end) = '\0';
+            buf[end] = '\0';
         }
         else {
             wcscat(buf, defpath);
@@ -881,18 +899,13 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
     wcscat(buf, delimiter);
 
     /* Finally, on goes the directory for dynamic-load modules */
-    wcscat(buf, config->exec_prefix);
+    wcscat(buf, exec_prefix);
 
-    return buf;
+    config->module_search_path = buf;
+    return _Py_INIT_OK();
 }
 
 
-#define DECODE_LOCALE_ERR(NAME, LEN) \
-    ((LEN) == (size_t)-2) \
-     ? _Py_INIT_USER_ERR("failed to decode " #NAME) \
-     : _Py_INIT_NO_MEMORY()
-
-
 static _PyInitError
 calculate_init(PyCalculatePath *calculate,
                const _PyMainInterpreterConfig *main_config)
@@ -941,15 +954,30 @@ calculate_free(PyCalculatePath *calculate)
 }
 
 
-static void
+static _PyInitError
 calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config)
 {
-    calculate_progpath(calculate, config);
-    calculate_argv0_path(calculate, config);
+    _PyInitError err = calculate_program_name(calculate, config);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+
+    err = calculate_argv0_path(calculate, config->program_name);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+
     calculate_read_pyenv(calculate);
-    calculate_prefix(calculate, config);
-    calculate_zip_path(calculate, config);
-    calculate_exec_prefix(calculate, config);
+
+    wchar_t prefix[MAXPATHLEN+1];
+    memset(prefix, 0, sizeof(prefix));
+    calculate_prefix(calculate, prefix);
+
+    calculate_zip_path(calculate, prefix);
+
+    wchar_t exec_prefix[MAXPATHLEN+1];
+    memset(exec_prefix, 0, sizeof(exec_prefix));
+    calculate_exec_prefix(calculate, exec_prefix);
 
     if ((!calculate->prefix_found || !calculate->exec_prefix_found) &&
         !Py_FrozenFlag)
@@ -958,53 +986,105 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config)
                 "Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
     }
 
-    config->module_search_path = calculate_module_search_path(calculate, config);
-    calculate_reduce_prefix(calculate, config);
-    calculate_reduce_exec_prefix(calculate, config);
+    err = calculate_module_search_path(calculate, prefix, exec_prefix,
+                                       config);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+
+    calculate_reduce_prefix(calculate, prefix);
+
+    config->prefix = _PyMem_RawWcsdup(prefix);
+    if (config->prefix == NULL) {
+        return _Py_INIT_NO_MEMORY();
+    }
+
+    calculate_reduce_exec_prefix(calculate, exec_prefix);
+
+    config->exec_prefix = _PyMem_RawWcsdup(exec_prefix);
+    if (config->exec_prefix == NULL) {
+        return _Py_INIT_NO_MEMORY();
+    }
+
+    return _Py_INIT_OK();
 }
 
 
 static void
-calculate_path(const _PyMainInterpreterConfig *main_config)
+pathconfig_clear(PyPathConfig *config)
 {
-    _PyInitError err;
-    PyCalculatePath calculate;
-    memset(&calculate, 0, sizeof(calculate));
+#define CLEAR(ATTR) \
+    do { \
+        PyMem_RawFree(ATTR); \
+        ATTR = NULL; \
+    } while (0)
+
+    CLEAR(config->prefix);
+    CLEAR(config->exec_prefix);
+    CLEAR(config->program_name);
+    CLEAR(config->module_search_path);
+#undef CLEAR
+}
 
-    _PyMainInterpreterConfig tmp_config;
-    int use_tmp = (main_config == NULL);
-    if (use_tmp) {
-        tmp_config = _PyMainInterpreterConfig_INIT;
-        err = _PyMainInterpreterConfig_ReadEnv(&tmp_config);
-        if (_Py_INIT_FAILED(err)) {
-            goto fatal_error;
-        }
-        main_config = &tmp_config;
+
+/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
+   and Py_GetProgramFullPath() */
+_PyInitError
+_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
+{
+    if (path_config.module_search_path) {
+        /* Already initialized */
+        return _Py_INIT_OK();
     }
 
-    err = calculate_init(&calculate, main_config);
+    PyCalculatePath calculate;
+    memset(&calculate, 0, sizeof(calculate));
+
+    _PyInitError err = calculate_init(&calculate, main_config);
     if (_Py_INIT_FAILED(err)) {
-        goto fatal_error;
+        goto done;
     }
 
     PyPathConfig new_path_config;
     memset(&new_path_config, 0, sizeof(new_path_config));
 
-    calculate_path_impl(&calculate, &new_path_config);
+    err = calculate_path_impl(&calculate, &new_path_config);
+    if (_Py_INIT_FAILED(err)) {
+        pathconfig_clear(&new_path_config);
+        goto done;
+    }
+
     path_config = new_path_config;
+    err = _Py_INIT_OK();
 
-    if (use_tmp) {
-        _PyMainInterpreterConfig_Clear(&tmp_config);
-    }
+done:
     calculate_free(&calculate);
-    return;
+    return err;
+}
+
+
+static void
+calculate_path(void)
+{
+    _PyInitError err;
+    _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT;
 
-fatal_error:
-    if (use_tmp) {
-        _PyMainInterpreterConfig_Clear(&tmp_config);
+    err = _PyMainInterpreterConfig_ReadEnv(&config);
+    if (!_Py_INIT_FAILED(err)) {
+        err = _PyPathConfig_Init(&config);
     }
-    calculate_free(&calculate);
-    _Py_FatalInitError(err);
+    _PyMainInterpreterConfig_Clear(&config);
+
+    if (_Py_INIT_FAILED(err)) {
+        _Py_FatalInitError(err);
+    }
+}
+
+
+void
+_PyPathConfig_Fini(void)
+{
+    pathconfig_clear(&path_config);
 }
 
 
@@ -1012,33 +1092,19 @@ calculate_path(const _PyMainInterpreterConfig *main_config)
 void
 Py_SetPath(const wchar_t *path)
 {
-    if (path_config.module_search_path != NULL) {
-        PyMem_RawFree(path_config.module_search_path);
-        path_config.module_search_path = NULL;
-    }
-
     if (path == NULL) {
+        pathconfig_clear(&path_config);
         return;
     }
 
-    wchar_t *program_name = Py_GetProgramName();
-    wcsncpy(path_config.program_name, program_name, MAXPATHLEN);
-    path_config.exec_prefix[0] = path_config.prefix[0] = L'\0';
-    size_t size = (wcslen(path) + 1) * sizeof(wchar_t);
-    path_config.module_search_path = PyMem_RawMalloc(size);
-    if (path_config.module_search_path != NULL) {
-        wcscpy(path_config.module_search_path, path);
-    }
-}
-
+    PyPathConfig new_config;
+    new_config.program_name = _PyMem_RawWcsdup(Py_GetProgramName());
+    new_config.exec_prefix = _PyMem_RawWcsdup(L"");
+    new_config.prefix = _PyMem_RawWcsdup(L"");
+    new_config.module_search_path = _PyMem_RawWcsdup(path);
 
-wchar_t *
-_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config)
-{
-    if (!path_config.module_search_path) {
-        calculate_path(main_config);
-    }
-    return path_config.module_search_path;
+    pathconfig_clear(&path_config);
+    path_config = new_config;
 }
 
 
@@ -1046,7 +1112,7 @@ wchar_t *
 Py_GetPath(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.module_search_path;
 }
@@ -1056,7 +1122,7 @@ wchar_t *
 Py_GetPrefix(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.prefix;
 }
@@ -1066,7 +1132,7 @@ wchar_t *
 Py_GetExecPrefix(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.exec_prefix;
 }
@@ -1076,7 +1142,7 @@ wchar_t *
 Py_GetProgramFullPath(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.program_name;
 }
diff --git a/Modules/main.c b/Modules/main.c
index dca165dad2c..1b1d8041ef1 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -38,14 +38,14 @@ extern "C" {
 
 #define DECODE_LOCALE_ERR(NAME, LEN) \
     (((LEN) == -2) \
-     ? _Py_INIT_USER_ERR("failed to decode " #NAME) \
+     ? _Py_INIT_USER_ERR("cannot decode " #NAME) \
      : _Py_INIT_NO_MEMORY())
 
 
 #define SET_DECODE_ERROR(NAME, LEN) \
     do { \
         if ((LEN) == (size_t)-2) { \
-            pymain->err = _Py_INIT_USER_ERR("failed to decode " #NAME); \
+            pymain->err = _Py_INIT_USER_ERR("cannot decode " #NAME); \
         } \
         else { \
             pymain->err = _Py_INIT_NO_MEMORY(); \
diff --git a/PC/getpathp.c b/PC/getpathp.c
index 38e433b6dcd..fe0226ba5d2 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -117,9 +117,9 @@
 #endif
 
 typedef struct {
-    wchar_t prefix[MAXPATHLEN+1];
-    wchar_t program_name[MAXPATHLEN+1];
-    wchar_t dllpath[MAXPATHLEN+1];
+    wchar_t *prefix;
+    wchar_t *program_name;
+    wchar_t *dll_path;
     wchar_t *module_search_path;
 } PyPathConfig;
 
@@ -483,24 +483,39 @@ getpythonregpath(HKEY keyBase, int skipcore)
 #endif /* Py_ENABLE_SHARED */
 
 
-static void
-get_progpath(PyCalculatePath *calculate, PyPathConfig *config)
+static _PyInitError
+get_dll_path(PyCalculatePath *calculate, PyPathConfig *config)
 {
-    wchar_t *path = calculate->path_env;
+    wchar_t dll_path[MAXPATHLEN+1];
+    memset(dll_path, 0, sizeof(dll_path));
 
 #ifdef Py_ENABLE_SHARED
     extern HANDLE PyWin_DLLhModule;
-    /* static init of program_name ensures final char remains \0 */
     if (PyWin_DLLhModule) {
-        if (!GetModuleFileNameW(PyWin_DLLhModule, config->dllpath, MAXPATHLEN)) {
-            config->dllpath[0] = 0;
+        if (!GetModuleFileNameW(PyWin_DLLhModule, dll_path, MAXPATHLEN)) {
+            dll_path[0] = 0;
         }
     }
 #else
-    config->dllpath[0] = 0;
+    dll_path[0] = 0;
 #endif
-    if (GetModuleFileNameW(NULL, config->program_name, MAXPATHLEN)) {
-        return;
+
+    config->dll_path = _PyMem_RawWcsdup(dll_path);
+    if (config->dll_path == NULL) {
+        return _Py_INIT_NO_MEMORY();
+    }
+    return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+get_program_name(PyCalculatePath *calculate, PyPathConfig *config)
+{
+    wchar_t program_name[MAXPATHLEN+1];
+    memset(program_name, 0, sizeof(program_name));
+
+    if (GetModuleFileNameW(NULL, program_name, MAXPATHLEN)) {
+        goto done;
     }
 
     /* If there is no slash in the argv0 path, then we have to
@@ -514,9 +529,10 @@ get_progpath(PyCalculatePath *calculate, PyPathConfig *config)
     if (wcschr(calculate->program_name, SEP))
 #endif
     {
-        wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN);
+        wcsncpy(program_name, calculate->program_name, MAXPATHLEN);
     }
-    else if (path) {
+    else if (calculate->path_env) {
+        wchar_t *path = calculate->path_env;
         while (1) {
             wchar_t *delim = wcschr(path, DELIM);
 
@@ -524,29 +540,36 @@ get_progpath(PyCalculatePath *calculate, PyPathConfig *config)
                 size_t len = delim - path;
                 /* ensure we can't overwrite buffer */
                 len = min(MAXPATHLEN,len);
-                wcsncpy(config->program_name, path, len);
-                *(config->program_name + len) = '\0';
+                wcsncpy(program_name, path, len);
+                program_name[len] = '\0';
             }
             else {
-                wcsncpy(config->program_name, path, MAXPATHLEN);
+                wcsncpy(program_name, path, MAXPATHLEN);
             }
 
             /* join() is safe for MAXPATHLEN+1 size buffer */
-            join(config->program_name, calculate->program_name);
-            if (exists(config->program_name)) {
+            join(program_name, calculate->program_name);
+            if (exists(program_name)) {
                 break;
             }
 
             if (!delim) {
-                config->program_name[0] = '\0';
+                program_name[0] = '\0';
                 break;
             }
             path = delim + 1;
         }
     }
     else {
-        config->program_name[0] = '\0';
+        program_name[0] = '\0';
+    }
+
+done:
+    config->program_name = _PyMem_RawWcsdup(program_name);
+    if (config->program_name == NULL) {
+        return _Py_INIT_NO_MEMORY();
     }
+    return _Py_INIT_OK();
 }
 
 
@@ -602,12 +625,13 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
 }
 
 
-static wchar_t*
-read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
+static int
+read_pth_file(PyPathConfig *config, wchar_t *prefix, const wchar_t *path,
+              int *isolated, int *nosite)
 {
     FILE *sp_file = _Py_wfopen(path, L"r");
     if (sp_file == NULL) {
-        return NULL;
+        return 0;
     }
 
     wcscpy_s(prefix, MAXPATHLEN+1, path);
@@ -680,12 +704,13 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
     }
 
     fclose(sp_file);
-    return buf;
+    config->module_search_path = buf;
+    return 1;
 
 error:
     PyMem_RawFree(buf);
     fclose(sp_file);
-    return NULL;
+    return 0;
 }
 
 
@@ -704,8 +729,8 @@ calculate_init(PyCalculatePath *calculate,
 static int
 get_pth_filename(wchar_t *spbuffer, PyPathConfig *config)
 {
-    if (config->dllpath[0]) {
-        if (!change_ext(spbuffer, config->dllpath, L"._pth") && exists(spbuffer)) {
+    if (config->dll_path[0]) {
+        if (!change_ext(spbuffer, config->dll_path, L"._pth") && exists(spbuffer)) {
             return 1;
         }
     }
@@ -719,7 +744,7 @@ get_pth_filename(wchar_t *spbuffer, PyPathConfig *config)
 
 
 static int
-calculate_pth_file(PyPathConfig *config)
+calculate_pth_file(PyPathConfig *config, wchar_t *prefix)
 {
     wchar_t spbuffer[MAXPATHLEN+1];
 
@@ -727,13 +752,8 @@ calculate_pth_file(PyPathConfig *config)
         return 0;
     }
 
-    config->module_search_path = read_pth_file(spbuffer, config->prefix,
-                                               &Py_IsolatedFlag,
-                                               &Py_NoSiteFlag);
-    if (!config->module_search_path) {
-        return 0;
-    }
-    return 1;
+    return read_pth_file(config, prefix, spbuffer,
+                         &Py_IsolatedFlag, &Py_NoSiteFlag);
 }
 
 
@@ -775,43 +795,34 @@ calculate_pyvenv_file(PyCalculatePath *calculate)
 }
 
 
-static void
-calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
-                    const _PyMainInterpreterConfig *main_config)
-{
-    get_progpath(calculate, config);
-    /* program_name guaranteed \0 terminated in MAXPATH+1 bytes. */
-    wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->program_name);
-    reduce(calculate->argv0_path);
+#define INIT_ERR_BUFFER_OVERFLOW() _Py_INIT_ERR("buffer overflow")
 
-    /* Search for a sys.path file */
-    if (calculate_pth_file(config)) {
-        return;
-    }
-
-    calculate_pyvenv_file(calculate);
-
-    /* Calculate zip archive path from DLL or exe path */
-    change_ext(calculate->zip_path,
-               config->dllpath[0] ? config->dllpath : config->program_name,
-               L".zip");
 
+static void
+calculate_home_prefix(PyCalculatePath *calculate, wchar_t *prefix)
+{
     if (calculate->home == NULL || *calculate->home == '\0') {
         if (calculate->zip_path[0] && exists(calculate->zip_path)) {
-            wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->zip_path);
-            reduce(config->prefix);
-            calculate->home = config->prefix;
-        } else if (search_for_prefix(config->prefix, calculate->argv0_path, LANDMARK)) {
-            calculate->home = config->prefix;
+            wcscpy_s(prefix, MAXPATHLEN+1, calculate->zip_path);
+            reduce(prefix);
+            calculate->home = prefix;
+        }
+        else if (search_for_prefix(prefix, calculate->argv0_path, LANDMARK)) {
+            calculate->home = prefix;
         }
         else {
             calculate->home = NULL;
         }
     }
     else {
-        wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->home);
+        wcscpy_s(prefix, MAXPATHLEN+1, calculate->home);
     }
+}
+
 
+static _PyInitError
+calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config, wchar_t *prefix)
+{
     int skiphome = calculate->home==NULL ? 0 : 1;
 #ifdef Py_ENABLE_SHARED
     calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);
@@ -873,34 +884,34 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
             fprintf(stderr, "Using default static path.\n");
             config->module_search_path = PYTHONPATH;
         }
-        return;
+        return _Py_INIT_OK();
     }
     start_buf = buf;
 
     if (calculate->module_search_path_env) {
         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->module_search_path_env)) {
-            Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
+            return INIT_ERR_BUFFER_OVERFLOW();
         }
         buf = wcschr(buf, L'\0');
         *buf++ = DELIM;
     }
     if (calculate->zip_path[0]) {
         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) {
-            Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
+            return INIT_ERR_BUFFER_OVERFLOW();
         }
         buf = wcschr(buf, L'\0');
         *buf++ = DELIM;
     }
     if (calculate->user_path) {
         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) {
-            Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
+            return INIT_ERR_BUFFER_OVERFLOW();
         }
         buf = wcschr(buf, L'\0');
         *buf++ = DELIM;
     }
     if (calculate->machine_path) {
         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) {
-            Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
+            return INIT_ERR_BUFFER_OVERFLOW();
         }
         buf = wcschr(buf, L'\0');
         *buf++ = DELIM;
@@ -908,7 +919,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
     if (calculate->home == NULL) {
         if (!skipdefault) {
             if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) {
-                Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
+                return INIT_ERR_BUFFER_OVERFLOW();
             }
             buf = wcschr(buf, L'\0');
             *buf++ = DELIM;
@@ -927,7 +938,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
             }
             if (p[0] == '.' && is_sep(p[1])) {
                 if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) {
-                    Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
+                    return INIT_ERR_BUFFER_OVERFLOW();
                 }
                 buf = wcschr(buf, L'\0');
                 p++;
@@ -957,7 +968,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
        on the path, and that our 'prefix' directory is
        the parent of that.
     */
-    if (config->prefix[0] == L'\0') {
+    if (prefix[0] == L'\0') {
         wchar_t lookBuf[MAXPATHLEN+1];
         wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
         while (1) {
@@ -974,7 +985,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
             lookBuf[nchars] = L'\0';
             /* Up one level to the parent */
             reduce(lookBuf);
-            if (search_for_prefix(config->prefix, lookBuf, LANDMARK)) {
+            if (search_for_prefix(prefix, lookBuf, LANDMARK)) {
                 break;
             }
             /* If we are out of paths to search - give up */
@@ -986,6 +997,59 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
     }
 
     config->module_search_path = start_buf;
+    return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
+                    const _PyMainInterpreterConfig *main_config)
+{
+    _PyInitError err;
+
+    err = get_dll_path(calculate, config);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+
+    err = get_program_name(calculate, config);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+
+    /* program_name guaranteed \0 terminated in MAXPATH+1 bytes. */
+    wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->program_name);
+    reduce(calculate->argv0_path);
+
+    wchar_t prefix[MAXPATHLEN+1];
+    memset(prefix, 0, sizeof(prefix));
+
+    /* Search for a sys.path file */
+    if (calculate_pth_file(config, prefix)) {
+        goto done;
+    }
+
+    calculate_pyvenv_file(calculate);
+
+    /* Calculate zip archive path from DLL or exe path */
+    change_ext(calculate->zip_path,
+               config->dll_path[0] ? config->dll_path : config->program_name,
+               L".zip");
+
+    calculate_home_prefix(calculate, prefix);
+
+    err = calculate_module_search_path(calculate, config, prefix);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+
+done:
+    config->prefix = _PyMem_RawWcsdup(prefix);
+    if (config->prefix == NULL) {
+        return _Py_INIT_NO_MEMORY();
+    }
+
+    return _Py_INIT_OK();
 }
 
 
@@ -996,47 +1060,85 @@ calculate_free(PyCalculatePath *calculate)
     PyMem_RawFree(calculate->user_path);
 }
 
+
 static void
-calculate_path(const _PyMainInterpreterConfig *main_config)
+pathconfig_clear(PyPathConfig *config)
 {
+#define CLEAR(ATTR) \
+    do { \
+        PyMem_RawFree(ATTR); \
+        ATTR = NULL; \
+    } while (0)
+
+    CLEAR(config->prefix);
+    CLEAR(config->program_name);
+    CLEAR(config->dll_path);
+    CLEAR(config->module_search_path);
+#undef CLEAR
+}
+
+
+/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
+   and Py_GetProgramFullPath() */
+_PyInitError
+_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
+{
+    if (path_config.module_search_path) {
+        /* Already initialized */
+        return _Py_INIT_OK();
+    }
+
     _PyInitError err;
+
     PyCalculatePath calculate;
     memset(&calculate, 0, sizeof(calculate));
 
-    _PyMainInterpreterConfig tmp_config;
-    int use_tmp = (main_config == NULL);
-    if (use_tmp) {
-        tmp_config = _PyMainInterpreterConfig_INIT;
-        err = _PyMainInterpreterConfig_ReadEnv(&tmp_config);
-        if (_Py_INIT_FAILED(err)) {
-            goto fatal_error;
-        }
-        main_config = &tmp_config;
-    }
-
     calculate_init(&calculate, main_config);
 
     PyPathConfig new_path_config;
     memset(&new_path_config, 0, sizeof(new_path_config));
 
-    calculate_path_impl(&calculate, &new_path_config, main_config);
+    err = calculate_path_impl(&calculate, &new_path_config, main_config);
+    if (_Py_INIT_FAILED(err)) {
+        goto done;
+    }
+
     path_config = new_path_config;
+    err = _Py_INIT_OK();
 
-    if (use_tmp) {
-        _PyMainInterpreterConfig_Clear(&tmp_config);
+done:
+    if (_Py_INIT_FAILED(err)) {
+        pathconfig_clear(&new_path_config);
     }
     calculate_free(&calculate);
-    return;
+    return err;
+}
 
-fatal_error:
-    if (use_tmp) {
-        _PyMainInterpreterConfig_Clear(&tmp_config);
+
+static void
+calculate_path(void)
+{
+    _PyInitError err;
+    _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT;
+
+    err = _PyMainInterpreterConfig_ReadEnv(&config);
+    if (!_Py_INIT_FAILED(err)) {
+        err = _PyPathConfig_Init(&config);
+    }
+    _PyMainInterpreterConfig_Clear(&config);
+
+    if (_Py_INIT_FAILED(err)) {
+        _Py_FatalInitError(err);
     }
-    calculate_free(&calculate);
-    _Py_FatalInitError(err);
 }
 
 
+void
+_PyPathConfig_Fini(void)
+{
+    pathconfig_clear(&path_config);
+}
+
 
 /* External interface */
 
@@ -1044,31 +1146,21 @@ void
 Py_SetPath(const wchar_t *path)
 {
     if (path_config.module_search_path != NULL) {
-        PyMem_RawFree(path_config.module_search_path);
-        path_config.module_search_path = NULL;
+        pathconfig_clear(&path_config);
     }
 
     if (path == NULL) {
         return;
     }
 
-    wchar_t *program_name = Py_GetProgramName();
-    wcsncpy(path_config.program_name, program_name, MAXPATHLEN);
-    path_config.prefix[0] = L'\0';
-    path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t));
-    if (path_config.module_search_path != NULL) {
-        wcscpy(path_config.module_search_path, path);
-    }
-}
-
+    PyPathConfig new_config;
+    new_config.program_name = _PyMem_RawWcsdup(Py_GetProgramName());
+    new_config.prefix = _PyMem_RawWcsdup(L"");
+    new_config.dll_path = _PyMem_RawWcsdup(L"");
+    new_config.module_search_path = _PyMem_RawWcsdup(path);
 
-wchar_t *
-_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config)
-{
-    if (!path_config.module_search_path) {
-        calculate_path(main_config);
-    }
-    return path_config.module_search_path;
+    pathconfig_clear(&path_config);
+    path_config = new_config;
 }
 
 
@@ -1076,7 +1168,7 @@ wchar_t *
 Py_GetPath(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.module_search_path;
 }
@@ -1086,7 +1178,7 @@ wchar_t *
 Py_GetPrefix(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.prefix;
 }
@@ -1103,7 +1195,7 @@ wchar_t *
 Py_GetProgramFullPath(void)
 {
     if (!path_config.module_search_path) {
-        calculate_path(NULL);
+        calculate_path();
     }
     return path_config.program_name;
 }
@@ -1129,7 +1221,7 @@ _Py_CheckPython3()
 
     /* If there is a python3.dll next to the python3y.dll,
        assume this is a build tree; use that DLL */
-    wcscpy(py3path, path_config.dllpath);
+    wcscpy(py3path, path_config.dll_path);
     s = wcsrchr(py3path, L'\\');
     if (!s) {
         s = py3path;
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 714be3768f6..868ac8450d4 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -866,11 +866,6 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
     /* Now finish configuring the main interpreter */
     interp->config = *config;
 
-    /* GetPath may initialize state that _PySys_EndInit locks
-       in, and so has to be called first. */
-    /* TODO: Call Py_GetPath() in Py_ReadConfig, rather than here */
-    wchar_t *sys_path = _Py_GetPathWithConfig(&interp->config);
-
     if (interp->core_config._disable_importlib) {
         /* Special mode for freeze_importlib: run with no import system
          *
@@ -880,11 +875,20 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
         _PyRuntime.initialized = 1;
         return _Py_INIT_OK();
     }
+
     /* TODO: Report exceptions rather than fatal errors below here */
 
     if (_PyTime_Init() < 0)
         return _Py_INIT_ERR("can't initialize time");
 
+    /* GetPath may initialize state that _PySys_EndInit locks
+       in, and so has to be called first. */
+    err = _PyPathConfig_Init(&interp->config);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+    wchar_t *sys_path = Py_GetPath();
+
     /* Finish setting up the sys module and import system */
     PySys_SetPath(sys_path);
     if (_PySys_EndInit(interp->sysdict) < 0)
@@ -1261,6 +1265,9 @@ Py_FinalizeEx(void)
 #endif
 
     call_ll_exitfuncs();
+
+    _PyPathConfig_Fini();
+
     _PyRuntime_Finalize();
     return status;
 }
@@ -1290,6 +1297,7 @@ new_interpreter(PyThreadState **tstate_p)
     PyInterpreterState *interp;
     PyThreadState *tstate, *save_tstate;
     PyObject *bimod, *sysmod;
+    _PyInitError err;
 
     if (!_PyRuntime.initialized) {
         return _Py_INIT_ERR("Py_Initialize must be called first");
@@ -1325,10 +1333,13 @@ new_interpreter(PyThreadState **tstate_p)
         interp->config = main_interp->config;
     }
 
-    /* XXX The following is lax in error checking */
-
-    wchar_t *sys_path = _Py_GetPathWithConfig(&interp->config);
+    err = _PyPathConfig_Init(&interp->config);
+    if (_Py_INIT_FAILED(err)) {
+        return err;
+    }
+    wchar_t *sys_path = Py_GetPath();
 
+    /* XXX The following is lax in error checking */
     PyObject *modules = PyDict_New();
     if (modules == NULL) {
         return _Py_INIT_ERR("can't make modules dictionary");
@@ -1359,7 +1370,6 @@ new_interpreter(PyThreadState **tstate_p)
 
     if (bimod != NULL && sysmod != NULL) {
         PyObject *pstderr;
-        _PyInitError err;
 
         /* Set up a preliminary stderr printer until we have enough
            infrastructure for the io module in place. */



More information about the Python-checkins mailing list