[Python-checkins] bpo-38234: Cleanup getpath.c (GH-16367)

Victor Stinner webhook-mailer at python.org
Tue Sep 24 20:54:29 EDT 2019


https://github.com/python/cpython/commit/221fd84703c545408bbb4a6e0b58459651331f5c
commit: 221fd84703c545408bbb4a6e0b58459651331f5c
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2019-09-25T02:54:25+02:00
summary:

bpo-38234: Cleanup getpath.c (GH-16367)

* search_for_prefix() directly calls reduce() if found is greater
  than 0.
* Add calculate_pybuilddir() subfunction.
* search_for_prefix(): add path string buffer for readability.
* Fix some error handling code paths: release resources on error.
* calculate_read_pyenv(): rename tmpbuffer to filename.
* test.pythoninfo now also logs windows.dll_path

files:
M Lib/test/pythoninfo.py
M Modules/getpath.c
M PC/getpathp.c

diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index 28a902355e8a..d2fa6c593659 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -673,6 +673,13 @@ def collect_windows(info_add):
         res = bool(RtlAreLongPathsEnabled())
     info_add('windows.RtlAreLongPathsEnabled', res)
 
+    try:
+        import _winapi
+        dll_path = _winapi.GetModuleFileName(sys.dllhandle)
+        info_add('windows.dll_path', dll_path)
+    except (ImportError, AttributeError):
+        pass
+
 
 def collect_info(info):
     error = False
diff --git a/Modules/getpath.c b/Modules/getpath.c
index a4607ef2d567..4246d4ca5ac0 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -370,12 +370,15 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
                   const wchar_t *argv0_path,
                   wchar_t *prefix, size_t prefix_len, int *found)
 {
+    wchar_t path[MAXPATHLEN+1];
+    memset(path, 0, sizeof(path));
+    size_t path_len = Py_ARRAY_LENGTH(path);
+
     PyStatus status;
-    size_t n;
-    wchar_t *vpath;
 
     /* If PYTHONHOME is set, we believe it unconditionally */
     if (pathconfig->home) {
+        /* Path: <home> / <lib_python> */
         if (safe_wcscpy(prefix, pathconfig->home, prefix_len) < 0) {
             return PATHLEN_ERR();
         }
@@ -387,27 +390,25 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
         if (_PyStatus_EXCEPTION(status)) {
             return status;
         }
-        status = joinpath(prefix, LANDMARK, prefix_len);
-        if (_PyStatus_EXCEPTION(status)) {
-            return status;
-        }
         *found = 1;
         return _PyStatus_OK();
     }
 
     /* Check to see if argv[0] is in the build directory */
-    if (safe_wcscpy(prefix, argv0_path, prefix_len) < 0) {
+    if (safe_wcscpy(path, argv0_path, path_len) < 0) {
         return PATHLEN_ERR();
     }
-    status = joinpath(prefix, L"Modules/Setup.local", prefix_len);
+    status = joinpath(path, L"Modules/Setup.local", path_len);
     if (_PyStatus_EXCEPTION(status)) {
         return status;
     }
 
-    if (isfile(prefix)) {
-        /* Check VPATH to see if argv0_path is in the build directory. */
-        vpath = Py_DecodeLocale(VPATH, NULL);
+    if (isfile(path)) {
+        /* Check VPATH to see if argv0_path is in the build directory.
+           VPATH can be empty. */
+        wchar_t *vpath = Py_DecodeLocale(VPATH, NULL);
         if (vpath != NULL) {
+            /* Path: <argv0_path> / <vpath> / Lib / LANDMARK */
             if (safe_wcscpy(prefix, argv0_path, prefix_len) < 0) {
                 return PATHLEN_ERR();
             }
@@ -428,6 +429,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
 
             if (ismodule(prefix, prefix_len)) {
                 *found = -1;
+                reduce(prefix);
                 return _PyStatus_OK();
             }
         }
@@ -440,7 +442,8 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
     }
 
     do {
-        n = wcslen(prefix);
+        /* Path: <argv0_path or substring> / <lib_python> / LANDMARK */
+        size_t n = wcslen(prefix);
         status = joinpath(prefix, calculate->lib_python, prefix_len);
         if (_PyStatus_EXCEPTION(status)) {
             return status;
@@ -452,13 +455,15 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
 
         if (ismodule(prefix, prefix_len)) {
             *found = 1;
+            reduce(prefix);
             return _PyStatus_OK();
         }
         prefix[n] = L'\0';
         reduce(prefix);
     } while (prefix[0]);
 
-    /* Look at configure's PREFIX */
+    /* Look at configure's PREFIX.
+       Path: <PREFIX macro> / <lib_python> / LANDMARK */
     if (safe_wcscpy(prefix, calculate->prefix, prefix_len) < 0) {
         return PATHLEN_ERR();
     }
@@ -473,6 +478,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
 
     if (ismodule(prefix, prefix_len)) {
         *found = 1;
+        reduce(prefix);
         return _PyStatus_OK();
     }
 
@@ -509,9 +515,6 @@ calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
             return status;
         }
     }
-    else {
-        reduce(prefix);
-    }
     return _PyStatus_OK();
 }
 
@@ -546,6 +549,67 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
 }
 
 
+static PyStatus
+calculate_pybuilddir(const wchar_t *argv0_path,
+                     wchar_t *exec_prefix, size_t exec_prefix_len,
+                     int *found)
+{
+    PyStatus status;
+
+    wchar_t filename[MAXPATHLEN+1];
+    memset(filename, 0, sizeof(filename));
+    size_t filename_len = Py_ARRAY_LENGTH(filename);
+
+    /* 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.
+
+       Filename: <argv0_path> / "pybuilddir.txt" */
+    if (safe_wcscpy(filename, argv0_path, filename_len) < 0) {
+        return PATHLEN_ERR();
+    }
+    status = joinpath(filename, L"pybuilddir.txt", filename_len);
+    if (_PyStatus_EXCEPTION(status)) {
+        return status;
+    }
+
+    if (!isfile(filename)) {
+        return _PyStatus_OK();
+    }
+
+    FILE *fp = _Py_wfopen(filename, L"rb");
+    if (fp == NULL) {
+        errno = 0;
+        return _PyStatus_OK();
+    }
+
+    char buf[MAXPATHLEN + 1];
+    size_t n = fread(buf, 1, Py_ARRAY_LENGTH(buf) - 1, fp);
+    buf[n] = '\0';
+    fclose(fp);
+
+    size_t dec_len;
+    wchar_t *pybuilddir = _Py_DecodeUTF8_surrogateescape(buf, n, &dec_len);
+    if (!pybuilddir) {
+        return DECODE_LOCALE_ERR("pybuilddir.txt", dec_len);
+    }
+
+    /* Path: <argv0_path> / <pybuilddir content> */
+    if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
+        PyMem_RawFree(pybuilddir);
+        return PATHLEN_ERR();
+    }
+    status = joinpath(exec_prefix, pybuilddir, exec_prefix_len);
+    PyMem_RawFree(pybuilddir);
+    if (_PyStatus_EXCEPTION(status)) {
+        return status;
+    }
+
+    *found = -1;
+    return _PyStatus_OK();
+}
+
+
 /* search_for_exec_prefix requires that argv0_path be no more than
    MAXPATHLEN bytes long.
 */
@@ -556,10 +620,10 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
                        int *found)
 {
     PyStatus status;
-    size_t n;
 
     /* If PYTHONHOME is set, we believe it unconditionally */
     if (pathconfig->home) {
+        /* Path: <home> / <lib_python> / "lib-dynload" */
         wchar_t *delim = wcschr(pathconfig->home, DELIM);
         if (delim) {
             if (safe_wcscpy(exec_prefix, delim+1, exec_prefix_len) < 0) {
@@ -583,47 +647,15 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
         return _PyStatus_OK();
     }
 
-    /* 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. */
-    if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
-        return PATHLEN_ERR();
-    }
-    status = joinpath(exec_prefix, L"pybuilddir.txt", exec_prefix_len);
+    /* Check for pybuilddir.txt */
+    assert(*found == 0);
+    status = calculate_pybuilddir(argv0_path, exec_prefix, exec_prefix_len,
+                                  found);
     if (_PyStatus_EXCEPTION(status)) {
         return status;
     }
-
-    if (isfile(exec_prefix)) {
-        FILE *f = _Py_wfopen(exec_prefix, L"rb");
-        if (f == NULL) {
-            errno = 0;
-        }
-        else {
-            char buf[MAXPATHLEN + 1];
-            n = fread(buf, 1, Py_ARRAY_LENGTH(buf) - 1, f);
-            buf[n] = '\0';
-            fclose(f);
-
-            wchar_t *pybuilddir;
-            size_t dec_len;
-            pybuilddir = _Py_DecodeUTF8_surrogateescape(buf, n, &dec_len);
-            if (!pybuilddir) {
-                return DECODE_LOCALE_ERR("pybuilddir.txt", dec_len);
-            }
-
-            if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
-                return PATHLEN_ERR();
-            }
-            status = joinpath(exec_prefix, pybuilddir, exec_prefix_len);
-            PyMem_RawFree(pybuilddir );
-            if (_PyStatus_EXCEPTION(status)) {
-                return status;
-            }
-
-            *found = -1;
-            return _PyStatus_OK();
-        }
+    if (*found) {
+        return _PyStatus_OK();
     }
 
     /* Search from argv0_path, until root is found */
@@ -633,7 +665,8 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
     }
 
     do {
-        n = wcslen(exec_prefix);
+        /* Path: <argv0_path or substring> / <lib_python> / "lib-dynload" */
+        size_t n = wcslen(exec_prefix);
         status = joinpath(exec_prefix, calculate->lib_python, exec_prefix_len);
         if (_PyStatus_EXCEPTION(status)) {
             return status;
@@ -650,7 +683,9 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
         reduce(exec_prefix);
     } while (exec_prefix[0]);
 
-    /* Look at configure's EXEC_PREFIX */
+    /* Look at configure's EXEC_PREFIX.
+
+       Path: <EXEC_PREFIX macro> / <lib_python> / "lib-dynload" */
     if (safe_wcscpy(exec_prefix, calculate->exec_prefix, exec_prefix_len) < 0) {
         return PATHLEN_ERR();
     }
@@ -962,43 +997,49 @@ calculate_read_pyenv(PyCalculatePath *calculate,
                      wchar_t *argv0_path, size_t argv0_path_len)
 {
     PyStatus status;
-    wchar_t tmpbuffer[MAXPATHLEN+1];
-    const size_t buflen = Py_ARRAY_LENGTH(tmpbuffer);
-    wchar_t *env_cfg = L"pyvenv.cfg";
+    const wchar_t *env_cfg = L"pyvenv.cfg";
     FILE *env_file;
 
-    if (safe_wcscpy(tmpbuffer, argv0_path, buflen) < 0) {
+    wchar_t filename[MAXPATHLEN+1];
+    const size_t filename_len = Py_ARRAY_LENGTH(filename);
+    memset(filename, 0, sizeof(filename));
+
+    /* Filename: <argv0_path_len> / "pyvenv.cfg" */
+    if (safe_wcscpy(filename, argv0_path, filename_len) < 0) {
         return PATHLEN_ERR();
     }
 
-    status = joinpath(tmpbuffer, env_cfg, buflen);
+    status = joinpath(filename, env_cfg, filename_len);
     if (_PyStatus_EXCEPTION(status)) {
         return status;
     }
-    env_file = _Py_wfopen(tmpbuffer, L"r");
+    env_file = _Py_wfopen(filename, L"r");
     if (env_file == NULL) {
         errno = 0;
 
-        reduce(tmpbuffer);
-        reduce(tmpbuffer);
-        status = joinpath(tmpbuffer, env_cfg, buflen);
+        /* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
+        reduce(filename);
+        reduce(filename);
+        status = joinpath(filename, env_cfg, filename_len);
         if (_PyStatus_EXCEPTION(status)) {
             return status;
         }
 
-        env_file = _Py_wfopen(tmpbuffer, L"r");
+        env_file = _Py_wfopen(filename, L"r");
         if (env_file == NULL) {
             errno = 0;
+            return _PyStatus_OK();
         }
     }
 
-    if (env_file == NULL) {
-        return _PyStatus_OK();
-    }
-
     /* Look for a 'home' variable and set argv0_path to it, if found */
-    if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, buflen)) {
-        if (safe_wcscpy(argv0_path, tmpbuffer, argv0_path_len) < 0) {
+    wchar_t home[MAXPATHLEN+1];
+    memset(home, 0, sizeof(home));
+
+    if (_Py_FindEnvConfigValue(env_file, L"home",
+                               home, Py_ARRAY_LENGTH(home))) {
+        if (safe_wcscpy(argv0_path, home, argv0_path_len) < 0) {
+            fclose(env_file);
             return PATHLEN_ERR();
         }
     }
@@ -1200,6 +1241,8 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
         return status;
     }
 
+    /* If a pyvenv.cfg configure file is found,
+       argv0_path is overriden with its 'home' variable. */
     status = calculate_read_pyenv(calculate,
                                   argv0_path, Py_ARRAY_LENGTH(argv0_path));
     if (_PyStatus_EXCEPTION(status)) {
diff --git a/PC/getpathp.c b/PC/getpathp.c
index c4c0636dddeb..0eb75b8daf31 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -757,34 +757,34 @@ static void
 calculate_pyvenv_file(PyCalculatePath *calculate,
                       wchar_t *argv0_path, size_t argv0_path_len)
 {
-    wchar_t envbuffer[MAXPATHLEN+1];
+    wchar_t filename[MAXPATHLEN+1];
     const wchar_t *env_cfg = L"pyvenv.cfg";
 
-    wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path);
-    join(envbuffer, env_cfg);
+    /* Filename: <argv0_path_len> / "pyvenv.cfg" */
+    wcscpy_s(filename, MAXPATHLEN+1, argv0_path);
+    join(filename, env_cfg);
 
-    FILE *env_file = _Py_wfopen(envbuffer, L"r");
+    FILE *env_file = _Py_wfopen(filename, L"r");
     if (env_file == NULL) {
         errno = 0;
 
-        reduce(envbuffer);
-        reduce(envbuffer);
-        join(envbuffer, env_cfg);
+        /* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
+        reduce(filename);
+        reduce(filename);
+        join(filename, env_cfg);
 
-        env_file = _Py_wfopen(envbuffer, L"r");
+        env_file = _Py_wfopen(filename, L"r");
         if (env_file == NULL) {
             errno = 0;
+            return;
         }
     }
 
-    if (env_file == NULL) {
-        return;
-    }
-
     /* Look for a 'home' variable and set argv0_path to it, if found */
-    wchar_t tmpbuffer[MAXPATHLEN+1];
-    if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, MAXPATHLEN)) {
-        wcscpy_s(argv0_path, argv0_path_len, tmpbuffer);
+    wchar_t home[MAXPATHLEN+1];
+    if (_Py_FindEnvConfigValue(env_file, L"home",
+                               home, Py_ARRAY_LENGTH(home))) {
+        wcscpy_s(argv0_path, argv0_path_len, home);
     }
     fclose(env_file);
 }



More information about the Python-checkins mailing list