1 
2 /* Return the initial module search path. */
3 /* Used by DOS, Windows 3.1, Windows 95/98, Windows NT. */
4 
5 /* ----------------------------------------------------------------
6    PATH RULES FOR WINDOWS:
7    This describes how sys.path is formed on Windows.  It describes the
8    functionality, not the implementation (ie, the order in which these
9    are actually fetched is different). The presence of a python._pth or
10    pythonXY._pth file alongside the program overrides these rules - see
11    below.
12 
13    * Python always adds an empty entry at the start, which corresponds
14      to the current directory.
15 
16    * If the PYTHONPATH env. var. exists, its entries are added next.
17 
18    * We look in the registry for "application paths" - that is, sub-keys
19      under the main PythonPath registry key.  These are added next (the
20      order of sub-key processing is undefined).
21      HKEY_CURRENT_USER is searched and added first.
22      HKEY_LOCAL_MACHINE is searched and added next.
23      (Note that all known installers only use HKLM, so HKCU is typically
24      empty)
25 
26    * We attempt to locate the "Python Home" - if the PYTHONHOME env var
27      is set, we believe it.  Otherwise, we use the path of our host .EXE's
28      to try and locate one of our "landmarks" and deduce our home.
29      - If we DO have a Python Home: The relevant sub-directories (Lib,
30        DLLs, etc) are based on the Python Home
31      - If we DO NOT have a Python Home, the core Python Path is
32        loaded from the registry.  This is the main PythonPath key,
33        and both HKLM and HKCU are combined to form the path)
34 
35    * Iff - we can not locate the Python Home, have not had a PYTHONPATH
36      specified, and can't locate any Registry entries (ie, we have _nothing_
37      we can assume is a good path), a default path with relative entries is
38      used (eg. .\Lib;.\DLLs, etc)
39 
40 
41    If a '._pth' file exists adjacent to the executable with the same base name
42    (e.g. python._pth adjacent to python.exe) or adjacent to the shared library
43    (e.g. python36._pth adjacent to python36.dll), it is used in preference to
44    the above process. The shared library file takes precedence over the
45    executable. The path file must contain a list of paths to add to sys.path,
46    one per line. Each path is relative to the directory containing the file.
47    Blank lines and comments beginning with '#' are permitted.
48 
49    In the presence of this ._pth file, no other paths are added to the search
50    path, the registry finder is not enabled, site.py is not imported and
51    isolated mode is enabled. The site package can be enabled by including a
52    line reading "import site"; no other imports are recognized. Any invalid
53    entry (other than directories that do not exist) will result in immediate
54    termination of the program.
55 
56 
57   The end result of all this is:
58   * When running python.exe, or any other .exe in the main Python directory
59     (either an installed version, or directly from the PCbuild directory),
60     the core path is deduced, and the core paths in the registry are
61     ignored.  Other "application paths" in the registry are always read.
62 
63   * When Python is hosted in another exe (different directory, embedded via
64     COM, etc), the Python Home will not be deduced, so the core path from
65     the registry is used.  Other "application paths" in the registry are
66     always read.
67 
68   * If Python can't find its home and there is no registry (eg, frozen
69     exe, some very strange installation setup) you get a path with
70     some default, but relative, paths.
71 
72   * An embedding application can use Py_SetPath() to override all of
73     these automatic path computations.
74 
75   * An install of Python can fully specify the contents of sys.path using
76     either a 'EXENAME._pth' or 'DLLNAME._pth' file, optionally including
77     "import site" to enable the site module.
78 
79    ---------------------------------------------------------------- */
80 
81 
82 #include "Python.h"
83 #include "pycore_initconfig.h"
84 #include "pycore_pystate.h"
85 #include "osdefs.h"
86 #include <wchar.h>
87 
88 #ifndef MS_WINDOWS
89 #error getpathp.c should only be built on Windows
90 #endif
91 
92 #include <windows.h>
93 #include <shlwapi.h>
94 
95 #ifdef HAVE_SYS_TYPES_H
96 #include <sys/types.h>
97 #endif /* HAVE_SYS_TYPES_H */
98 
99 #ifdef HAVE_SYS_STAT_H
100 #include <sys/stat.h>
101 #endif /* HAVE_SYS_STAT_H */
102 
103 #include <string.h>
104 
105 /* Search in some common locations for the associated Python libraries.
106  *
107  * Py_GetPath() tries to return a sensible Python module search path.
108  *
109  * The approach is an adaptation for Windows of the strategy used in
110  * ../Modules/getpath.c; it uses the Windows Registry as one of its
111  * information sources.
112  *
113  * Py_SetPath() can be used to override this mechanism.  Call Py_SetPath
114  * with a semicolon separated path prior to calling Py_Initialize.
115  */
116 
117 #ifndef LANDMARK
118 #  define LANDMARK L"lib\\os.py"
119 #endif
120 
121 #define INIT_ERR_BUFFER_OVERFLOW() _PyStatus_ERR("buffer overflow")
122 
123 
124 typedef struct {
125     const wchar_t *path_env;           /* PATH environment variable */
126     const wchar_t *home;               /* PYTHONHOME environment variable */
127 
128     /* Registry key "Software\Python\PythonCore\X.Y\PythonPath"
129        where X.Y is the Python version (major.minor) */
130     wchar_t *machine_path;   /* from HKEY_LOCAL_MACHINE */
131     wchar_t *user_path;      /* from HKEY_CURRENT_USER */
132 
133     const wchar_t *pythonpath_env;
134 } PyCalculatePath;
135 
136 
137 /* determine if "ch" is a separator character */
138 static int
is_sep(wchar_t ch)139 is_sep(wchar_t ch)
140 {
141 #ifdef ALTSEP
142     return ch == SEP || ch == ALTSEP;
143 #else
144     return ch == SEP;
145 #endif
146 }
147 
148 
149 /* assumes 'dir' null terminated in bounds.  Never writes
150    beyond existing terminator. */
151 static void
reduce(wchar_t * dir)152 reduce(wchar_t *dir)
153 {
154     size_t i = wcsnlen_s(dir, MAXPATHLEN+1);
155     if (i >= MAXPATHLEN+1) {
156         Py_FatalError("buffer overflow in getpathp.c's reduce()");
157     }
158 
159     while (i > 0 && !is_sep(dir[i]))
160         --i;
161     dir[i] = '\0';
162 }
163 
164 
165 static int
change_ext(wchar_t * dest,const wchar_t * src,const wchar_t * ext)166 change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
167 {
168     if (src && src != dest) {
169         size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
170         size_t i = src_len;
171         if (i >= MAXPATHLEN+1) {
172             Py_FatalError("buffer overflow in getpathp.c's reduce()");
173         }
174 
175         while (i > 0 && src[i] != '.' && !is_sep(src[i]))
176             --i;
177 
178         if (i == 0) {
179             dest[0] = '\0';
180             return -1;
181         }
182 
183         if (is_sep(src[i])) {
184             i = src_len;
185         }
186 
187         if (wcsncpy_s(dest, MAXPATHLEN+1, src, i)) {
188             dest[0] = '\0';
189             return -1;
190         }
191     } else {
192         wchar_t *s = wcsrchr(dest, L'.');
193         if (s) {
194             s[0] = '\0';
195         }
196     }
197 
198     if (wcscat_s(dest, MAXPATHLEN+1, ext)) {
199         dest[0] = '\0';
200         return -1;
201     }
202 
203     return 0;
204 }
205 
206 
207 static int
exists(const wchar_t * filename)208 exists(const wchar_t *filename)
209 {
210     return GetFileAttributesW(filename) != 0xFFFFFFFF;
211 }
212 
213 
214 /* Is module -- check for .pyc too.
215    Assumes 'filename' MAXPATHLEN+1 bytes long -
216    may extend 'filename' by one character. */
217 static int
ismodule(wchar_t * filename,int update_filename)218 ismodule(wchar_t *filename, int update_filename)
219 {
220     size_t n;
221 
222     if (exists(filename)) {
223         return 1;
224     }
225 
226     /* Check for the compiled version of prefix. */
227     n = wcsnlen_s(filename, MAXPATHLEN+1);
228     if (n < MAXPATHLEN) {
229         int exist = 0;
230         filename[n] = L'c';
231         filename[n + 1] = L'\0';
232         exist = exists(filename);
233         if (!update_filename) {
234             filename[n] = L'\0';
235         }
236         return exist;
237     }
238     return 0;
239 }
240 
241 
242 /* Add a path component, by appending stuff to buffer.
243    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
244    NUL-terminated string with no more than MAXPATHLEN characters (not counting
245    the trailing NUL).  It's a fatal error if it contains a string longer than
246    that (callers must be careful!).  If these requirements are met, it's
247    guaranteed that buffer will still be a NUL-terminated string with no more
248    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
249    stuff as fits will be appended.
250 */
251 
252 static int _PathCchCombineEx_Initialized = 0;
253 typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut,
254                                                PCWSTR pszPathIn, PCWSTR pszMore,
255                                                unsigned long dwFlags);
256 static PPathCchCombineEx _PathCchCombineEx;
257 
258 static void
join(wchar_t * buffer,const wchar_t * stuff)259 join(wchar_t *buffer, const wchar_t *stuff)
260 {
261     if (_PathCchCombineEx_Initialized == 0) {
262         HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL,
263                                          LOAD_LIBRARY_SEARCH_SYSTEM32);
264         if (pathapi) {
265             _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx");
266         }
267         else {
268             _PathCchCombineEx = NULL;
269         }
270         _PathCchCombineEx_Initialized = 1;
271     }
272 
273     if (_PathCchCombineEx) {
274         if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) {
275             Py_FatalError("buffer overflow in getpathp.c's join()");
276         }
277     } else {
278         if (!PathCombineW(buffer, buffer, stuff)) {
279             Py_FatalError("buffer overflow in getpathp.c's join()");
280         }
281     }
282 }
283 
284 static int _PathCchCanonicalizeEx_Initialized = 0;
285 typedef HRESULT(__stdcall *PPathCchCanonicalizeEx) (PWSTR pszPathOut, size_t cchPathOut,
286     PCWSTR pszPathIn, unsigned long dwFlags);
287 static PPathCchCanonicalizeEx _PathCchCanonicalizeEx;
288 
289 /* Call PathCchCanonicalizeEx(path): remove navigation elements such as "."
290    and ".." to produce a direct, well-formed path. */
291 static PyStatus
canonicalize(wchar_t * buffer,const wchar_t * path)292 canonicalize(wchar_t *buffer, const wchar_t *path)
293 {
294     if (buffer == NULL) {
295         return _PyStatus_NO_MEMORY();
296     }
297 
298     if (_PathCchCanonicalizeEx_Initialized == 0) {
299         HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL,
300                                          LOAD_LIBRARY_SEARCH_SYSTEM32);
301         if (pathapi) {
302             _PathCchCanonicalizeEx = (PPathCchCanonicalizeEx)GetProcAddress(pathapi, "PathCchCanonicalizeEx");
303         }
304         else {
305             _PathCchCanonicalizeEx = NULL;
306         }
307         _PathCchCanonicalizeEx_Initialized = 1;
308     }
309 
310     if (_PathCchCanonicalizeEx) {
311         if (FAILED(_PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) {
312             return INIT_ERR_BUFFER_OVERFLOW();
313         }
314     }
315     else {
316         if (!PathCanonicalizeW(buffer, path)) {
317             return INIT_ERR_BUFFER_OVERFLOW();
318         }
319     }
320     return _PyStatus_OK();
321 }
322 
323 
324 /* gotlandmark only called by search_for_prefix, which ensures
325    'prefix' is null terminated in bounds.  join() ensures
326    'landmark' can not overflow prefix if too long. */
327 static int
gotlandmark(const wchar_t * prefix,const wchar_t * landmark)328 gotlandmark(const wchar_t *prefix, const wchar_t *landmark)
329 {
330     wchar_t filename[MAXPATHLEN+1];
331     memset(filename, 0, sizeof(filename));
332     wcscpy_s(filename, Py_ARRAY_LENGTH(filename), prefix);
333     join(filename, landmark);
334     return ismodule(filename, FALSE);
335 }
336 
337 
338 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
339    assumption provided by only caller, calculate_path() */
340 static int
search_for_prefix(wchar_t * prefix,const wchar_t * argv0_path,const wchar_t * landmark)341 search_for_prefix(wchar_t *prefix, const wchar_t *argv0_path, const wchar_t *landmark)
342 {
343     /* Search from argv0_path, until landmark is found */
344     wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
345     do {
346         if (gotlandmark(prefix, landmark)) {
347             return 1;
348         }
349         reduce(prefix);
350     } while (prefix[0]);
351     return 0;
352 }
353 
354 
355 static int
get_dllpath(wchar_t * dllpath)356 get_dllpath(wchar_t *dllpath)
357 {
358 #ifdef Py_ENABLE_SHARED
359     extern HANDLE PyWin_DLLhModule;
360     if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) {
361         return 0;
362     }
363 #endif
364     return -1;
365 }
366 
367 
368 #ifdef Py_ENABLE_SHARED
369 
370 /* a string loaded from the DLL at startup.*/
371 extern const char *PyWin_DLLVersionString;
372 
373 /* Load a PYTHONPATH value from the registry.
374    Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
375 
376    Works in both Unicode and 8bit environments.  Only uses the
377    Ex family of functions so it also works with Windows CE.
378 
379    Returns NULL, or a pointer that should be freed.
380 
381    XXX - this code is pretty strange, as it used to also
382    work on Win16, where the buffer sizes werent available
383    in advance.  It could be simplied now Win16/Win32s is dead!
384 */
385 static wchar_t *
getpythonregpath(HKEY keyBase,int skipcore)386 getpythonregpath(HKEY keyBase, int skipcore)
387 {
388     HKEY newKey = 0;
389     DWORD dataSize = 0;
390     DWORD numKeys = 0;
391     LONG rc;
392     wchar_t *retval = NULL;
393     WCHAR *dataBuf = NULL;
394     static const WCHAR keyPrefix[] = L"Software\\Python\\PythonCore\\";
395     static const WCHAR keySuffix[] = L"\\PythonPath";
396     size_t versionLen, keyBufLen;
397     DWORD index;
398     WCHAR *keyBuf = NULL;
399     WCHAR *keyBufPtr;
400     WCHAR **ppPaths = NULL;
401 
402     /* Tried to use sysget("winver") but here is too early :-( */
403     versionLen = strlen(PyWin_DLLVersionString);
404     /* Space for all the chars, plus one \0 */
405     keyBufLen = sizeof(keyPrefix) +
406                 sizeof(WCHAR)*(versionLen-1) +
407                 sizeof(keySuffix);
408     keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen);
409     if (keyBuf==NULL) {
410         goto done;
411     }
412 
413     memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
414     keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1;
415     mbstowcs(keyBufPtr, PyWin_DLLVersionString, versionLen);
416     keyBufPtr += versionLen;
417     /* NULL comes with this one! */
418     memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
419     /* Open the root Python key */
420     rc=RegOpenKeyExW(keyBase,
421                     keyBuf, /* subkey */
422             0, /* reserved */
423             KEY_READ,
424             &newKey);
425     if (rc!=ERROR_SUCCESS) {
426         goto done;
427     }
428     /* Find out how big our core buffer is, and how many subkeys we have */
429     rc = RegQueryInfoKeyW(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
430                     NULL, NULL, &dataSize, NULL, NULL);
431     if (rc!=ERROR_SUCCESS) {
432         goto done;
433     }
434     if (skipcore) {
435         dataSize = 0; /* Only count core ones if we want them! */
436     }
437     /* Allocate a temp array of char buffers, so we only need to loop
438        reading the registry once
439     */
440     ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys );
441     if (ppPaths==NULL) {
442         goto done;
443     }
444     memset(ppPaths, 0, sizeof(WCHAR *) * numKeys);
445     /* Loop over all subkeys, allocating a temp sub-buffer. */
446     for(index=0;index<numKeys;index++) {
447         WCHAR keyBuf[MAX_PATH+1];
448         HKEY subKey = 0;
449         DWORD reqdSize = MAX_PATH+1;
450         /* Get the sub-key name */
451         DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
452                                  NULL, NULL, NULL, NULL );
453         if (rc!=ERROR_SUCCESS) {
454             goto done;
455         }
456         /* Open the sub-key */
457         rc=RegOpenKeyExW(newKey,
458                                         keyBuf, /* subkey */
459                         0, /* reserved */
460                         KEY_READ,
461                         &subKey);
462         if (rc!=ERROR_SUCCESS) {
463             goto done;
464         }
465         /* Find the value of the buffer size, malloc, then read it */
466         RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
467         if (reqdSize) {
468             ppPaths[index] = PyMem_RawMalloc(reqdSize);
469             if (ppPaths[index]) {
470                 RegQueryValueExW(subKey, NULL, 0, NULL,
471                                 (LPBYTE)ppPaths[index],
472                                 &reqdSize);
473                 dataSize += reqdSize + 1; /* 1 for the ";" */
474             }
475         }
476         RegCloseKey(subKey);
477     }
478 
479     /* return null if no path to return */
480     if (dataSize == 0) {
481         goto done;
482     }
483 
484     /* original datasize from RegQueryInfo doesn't include the \0 */
485     dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
486     if (dataBuf) {
487         WCHAR *szCur = dataBuf;
488         /* Copy our collected strings */
489         for (index=0;index<numKeys;index++) {
490             if (index > 0) {
491                 *(szCur++) = L';';
492                 dataSize--;
493             }
494             if (ppPaths[index]) {
495                 Py_ssize_t len = wcslen(ppPaths[index]);
496                 wcsncpy(szCur, ppPaths[index], len);
497                 szCur += len;
498                 assert(dataSize > (DWORD)len);
499                 dataSize -= (DWORD)len;
500             }
501         }
502         if (skipcore) {
503             *szCur = '\0';
504         }
505         else {
506             /* If we have no values, we don't need a ';' */
507             if (numKeys) {
508                 *(szCur++) = L';';
509                 dataSize--;
510             }
511             /* Now append the core path entries -
512                this will include the NULL
513             */
514             rc = RegQueryValueExW(newKey, NULL, 0, NULL,
515                                   (LPBYTE)szCur, &dataSize);
516             if (rc != ERROR_SUCCESS) {
517                 PyMem_RawFree(dataBuf);
518                 goto done;
519             }
520         }
521         /* And set the result - caller must free */
522         retval = dataBuf;
523     }
524 done:
525     /* Loop freeing my temp buffers */
526     if (ppPaths) {
527         for(index=0; index<numKeys; index++)
528             PyMem_RawFree(ppPaths[index]);
529         PyMem_RawFree(ppPaths);
530     }
531     if (newKey) {
532         RegCloseKey(newKey);
533     }
534     PyMem_RawFree(keyBuf);
535     return retval;
536 }
537 #endif /* Py_ENABLE_SHARED */
538 
539 
540 static PyStatus
get_program_full_path(_PyPathConfig * pathconfig)541 get_program_full_path(_PyPathConfig *pathconfig)
542 {
543     PyStatus status;
544     const wchar_t *pyvenv_launcher;
545     wchar_t program_full_path[MAXPATHLEN+1];
546     memset(program_full_path, 0, sizeof(program_full_path));
547 
548     if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
549         /* GetModuleFileName should never fail when passed NULL */
550         return _PyStatus_ERR("Cannot determine program path");
551     }
552 
553     /* The launcher may need to force the executable path to a
554      * different environment, so override it here. */
555     pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
556     if (pyvenv_launcher && pyvenv_launcher[0]) {
557         /* If overridden, preserve the original full path */
558         if (pathconfig->base_executable == NULL) {
559             pathconfig->base_executable = PyMem_RawMalloc(
560                 sizeof(wchar_t) * (MAXPATHLEN + 1));
561             if (pathconfig->base_executable == NULL) {
562                 return _PyStatus_NO_MEMORY();
563             }
564 
565             status = canonicalize(pathconfig->base_executable,
566                                   program_full_path);
567             if (_PyStatus_EXCEPTION(status)) {
568                 return status;
569             }
570         }
571 
572         wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
573         /* bpo-35873: Clear the environment variable to avoid it being
574         * inherited by child processes. */
575         _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
576     }
577 
578     if (pathconfig->program_full_path == NULL) {
579         pathconfig->program_full_path = PyMem_RawMalloc(
580             sizeof(wchar_t) * (MAXPATHLEN + 1));
581         if (pathconfig->program_full_path == NULL) {
582             return _PyStatus_NO_MEMORY();
583         }
584 
585         status = canonicalize(pathconfig->program_full_path,
586                               program_full_path);
587         if (_PyStatus_EXCEPTION(status)) {
588             return status;
589         }
590     }
591     return _PyStatus_OK();
592 }
593 
594 
595 static PyStatus
read_pth_file(_PyPathConfig * pathconfig,wchar_t * prefix,const wchar_t * path,int * found)596 read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path,
597               int *found)
598 {
599     PyStatus status;
600     wchar_t *buf = NULL;
601     wchar_t *wline = NULL;
602     FILE *sp_file;
603 
604     sp_file = _Py_wfopen(path, L"r");
605     if (sp_file == NULL) {
606         return _PyStatus_OK();
607     }
608 
609     wcscpy_s(prefix, MAXPATHLEN+1, path);
610     reduce(prefix);
611     pathconfig->isolated = 1;
612     pathconfig->site_import = 0;
613 
614     size_t bufsiz = MAXPATHLEN;
615     size_t prefixlen = wcslen(prefix);
616 
617     buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
618     if (buf == NULL) {
619         status = _PyStatus_NO_MEMORY();
620         goto done;
621     }
622     buf[0] = '\0';
623 
624     while (!feof(sp_file)) {
625         char line[MAXPATHLEN + 1];
626         char *p = fgets(line, Py_ARRAY_LENGTH(line), sp_file);
627         if (!p) {
628             break;
629         }
630         if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') {
631             continue;
632         }
633         while (*++p) {
634             if (*p == '\r' || *p == '\n') {
635                 *p = '\0';
636                 break;
637             }
638         }
639 
640         if (strcmp(line, "import site") == 0) {
641             pathconfig->site_import = 1;
642             continue;
643         }
644         else if (strncmp(line, "import ", 7) == 0) {
645             status = _PyStatus_ERR("only 'import site' is supported "
646                                    "in ._pth file");
647             goto done;
648         }
649 
650         DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
651         wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
652         if (wline == NULL) {
653             status = _PyStatus_NO_MEMORY();
654             goto done;
655         }
656         wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
657         wline[wn] = '\0';
658 
659         size_t usedsiz = wcslen(buf);
660         while (usedsiz + wn + prefixlen + 4 > bufsiz) {
661             bufsiz += MAXPATHLEN;
662             wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
663                                                             sizeof(wchar_t));
664             if (tmp == NULL) {
665                 status = _PyStatus_NO_MEMORY();
666                 goto done;
667             }
668             buf = tmp;
669         }
670 
671         if (usedsiz) {
672             wcscat_s(buf, bufsiz, L";");
673             usedsiz += 1;
674         }
675 
676         errno_t result;
677         _Py_BEGIN_SUPPRESS_IPH
678         result = wcscat_s(buf, bufsiz, prefix);
679         _Py_END_SUPPRESS_IPH
680 
681         if (result == EINVAL) {
682             status = _PyStatus_ERR("invalid argument during ._pth processing");
683             goto done;
684         } else if (result == ERANGE) {
685             status = _PyStatus_ERR("buffer overflow during ._pth processing");
686             goto done;
687         }
688 
689         wchar_t *b = &buf[usedsiz];
690         join(b, wline);
691 
692         PyMem_RawFree(wline);
693         wline = NULL;
694     }
695 
696     if (pathconfig->module_search_path == NULL) {
697         pathconfig->module_search_path = _PyMem_RawWcsdup(buf);
698         if (pathconfig->module_search_path == NULL) {
699             status = _PyStatus_NO_MEMORY();
700             goto done;
701         }
702     }
703 
704     *found = 1;
705     status = _PyStatus_OK();
706     goto done;
707 
708 done:
709     PyMem_RawFree(buf);
710     PyMem_RawFree(wline);
711     fclose(sp_file);
712     return status;
713 }
714 
715 
716 static int
get_pth_filename(PyCalculatePath * calculate,wchar_t * filename,const _PyPathConfig * pathconfig)717 get_pth_filename(PyCalculatePath *calculate, wchar_t *filename,
718                  const _PyPathConfig *pathconfig)
719 {
720     if (!get_dllpath(filename) &&
721         !change_ext(filename, filename, L"._pth") &&
722         exists(filename))
723     {
724         return 1;
725     }
726     if (pathconfig->program_full_path[0] &&
727         !change_ext(filename, pathconfig->program_full_path, L"._pth") &&
728         exists(filename))
729     {
730         return 1;
731     }
732     return 0;
733 }
734 
735 
736 static PyStatus
calculate_pth_file(PyCalculatePath * calculate,_PyPathConfig * pathconfig,wchar_t * prefix,int * found)737 calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
738                    wchar_t *prefix, int *found)
739 {
740     wchar_t filename[MAXPATHLEN+1];
741 
742     if (!get_pth_filename(calculate, filename, pathconfig)) {
743         return _PyStatus_OK();
744     }
745 
746     return read_pth_file(pathconfig, prefix, filename, found);
747 }
748 
749 
750 /* Search for an environment configuration file, first in the
751    executable's directory and then in the parent directory.
752    If found, open it for use when searching for prefixes.
753 */
754 static void
calculate_pyvenv_file(PyCalculatePath * calculate,wchar_t * argv0_path,size_t argv0_path_len)755 calculate_pyvenv_file(PyCalculatePath *calculate,
756                       wchar_t *argv0_path, size_t argv0_path_len)
757 {
758     wchar_t filename[MAXPATHLEN+1];
759     const wchar_t *env_cfg = L"pyvenv.cfg";
760 
761     /* Filename: <argv0_path_len> / "pyvenv.cfg" */
762     wcscpy_s(filename, MAXPATHLEN+1, argv0_path);
763     join(filename, env_cfg);
764 
765     FILE *env_file = _Py_wfopen(filename, L"r");
766     if (env_file == NULL) {
767         errno = 0;
768 
769         /* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
770         reduce(filename);
771         reduce(filename);
772         join(filename, env_cfg);
773 
774         env_file = _Py_wfopen(filename, L"r");
775         if (env_file == NULL) {
776             errno = 0;
777             return;
778         }
779     }
780 
781     /* Look for a 'home' variable and set argv0_path to it, if found */
782     wchar_t home[MAXPATHLEN+1];
783     if (_Py_FindEnvConfigValue(env_file, L"home",
784                                home, Py_ARRAY_LENGTH(home))) {
785         wcscpy_s(argv0_path, argv0_path_len, home);
786     }
787     fclose(env_file);
788 }
789 
790 
791 static void
calculate_home_prefix(PyCalculatePath * calculate,const wchar_t * argv0_path,const wchar_t * zip_path,wchar_t * prefix)792 calculate_home_prefix(PyCalculatePath *calculate,
793                       const wchar_t *argv0_path,
794                       const wchar_t *zip_path,
795                       wchar_t *prefix)
796 {
797     if (calculate->home == NULL || *calculate->home == '\0') {
798         if (zip_path[0] && exists(zip_path)) {
799             wcscpy_s(prefix, MAXPATHLEN+1, zip_path);
800             reduce(prefix);
801             calculate->home = prefix;
802         }
803         else if (search_for_prefix(prefix, argv0_path, LANDMARK)) {
804             calculate->home = prefix;
805         }
806         else {
807             calculate->home = NULL;
808         }
809     }
810     else {
811         wcscpy_s(prefix, MAXPATHLEN+1, calculate->home);
812     }
813 }
814 
815 
816 static PyStatus
calculate_module_search_path(PyCalculatePath * calculate,_PyPathConfig * pathconfig,const wchar_t * argv0_path,wchar_t * prefix,const wchar_t * zip_path)817 calculate_module_search_path(PyCalculatePath *calculate,
818                              _PyPathConfig *pathconfig,
819                              const wchar_t *argv0_path,
820                              wchar_t *prefix,
821                              const wchar_t *zip_path)
822 {
823     int skiphome = calculate->home==NULL ? 0 : 1;
824 #ifdef Py_ENABLE_SHARED
825     calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);
826     calculate->user_path = getpythonregpath(HKEY_CURRENT_USER, skiphome);
827 #endif
828     /* We only use the default relative PYTHONPATH if we haven't
829        anything better to use! */
830     int skipdefault = (calculate->pythonpath_env != NULL ||
831                        calculate->home != NULL ||
832                        calculate->machine_path != NULL ||
833                        calculate->user_path != NULL);
834 
835     /* We need to construct a path from the following parts.
836        (1) the PYTHONPATH environment variable, if set;
837        (2) for Win32, the zip archive file path;
838        (3) for Win32, the machine_path and user_path, if set;
839        (4) the PYTHONPATH config macro, with the leading "."
840            of each component replaced with home, if set;
841        (5) the directory containing the executable (argv0_path).
842        The length calculation calculates #4 first.
843        Extra rules:
844        - If PYTHONHOME is set (in any way) item (3) is ignored.
845        - If registry values are used, (4) and (5) are ignored.
846     */
847 
848     /* Calculate size of return buffer */
849     size_t bufsz = 0;
850     if (calculate->home != NULL) {
851         const wchar_t *p;
852         bufsz = 1;
853         for (p = PYTHONPATH; *p; p++) {
854             if (*p == DELIM) {
855                 bufsz++; /* number of DELIM plus one */
856             }
857         }
858         bufsz *= wcslen(calculate->home);
859     }
860     bufsz += wcslen(PYTHONPATH) + 1;
861     bufsz += wcslen(argv0_path) + 1;
862     if (calculate->user_path) {
863         bufsz += wcslen(calculate->user_path) + 1;
864     }
865     if (calculate->machine_path) {
866         bufsz += wcslen(calculate->machine_path) + 1;
867     }
868     bufsz += wcslen(zip_path) + 1;
869     if (calculate->pythonpath_env != NULL) {
870         bufsz += wcslen(calculate->pythonpath_env) + 1;
871     }
872 
873     wchar_t *buf, *start_buf;
874     buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
875     if (buf == NULL) {
876         return _PyStatus_NO_MEMORY();
877     }
878     start_buf = buf;
879 
880     if (calculate->pythonpath_env) {
881         if (wcscpy_s(buf, bufsz - (buf - start_buf),
882                      calculate->pythonpath_env)) {
883             return INIT_ERR_BUFFER_OVERFLOW();
884         }
885         buf = wcschr(buf, L'\0');
886         *buf++ = DELIM;
887     }
888     if (zip_path[0]) {
889         if (wcscpy_s(buf, bufsz - (buf - start_buf), zip_path)) {
890             return INIT_ERR_BUFFER_OVERFLOW();
891         }
892         buf = wcschr(buf, L'\0');
893         *buf++ = DELIM;
894     }
895     if (calculate->user_path) {
896         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) {
897             return INIT_ERR_BUFFER_OVERFLOW();
898         }
899         buf = wcschr(buf, L'\0');
900         *buf++ = DELIM;
901     }
902     if (calculate->machine_path) {
903         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) {
904             return INIT_ERR_BUFFER_OVERFLOW();
905         }
906         buf = wcschr(buf, L'\0');
907         *buf++ = DELIM;
908     }
909     if (calculate->home == NULL) {
910         if (!skipdefault) {
911             if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) {
912                 return INIT_ERR_BUFFER_OVERFLOW();
913             }
914             buf = wcschr(buf, L'\0');
915             *buf++ = DELIM;
916         }
917     } else {
918         const wchar_t *p = PYTHONPATH;
919         const wchar_t *q;
920         size_t n;
921         for (;;) {
922             q = wcschr(p, DELIM);
923             if (q == NULL) {
924                 n = wcslen(p);
925             }
926             else {
927                 n = q-p;
928             }
929             if (p[0] == '.' && is_sep(p[1])) {
930                 if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) {
931                     return INIT_ERR_BUFFER_OVERFLOW();
932                 }
933                 buf = wcschr(buf, L'\0');
934                 p++;
935                 n--;
936             }
937             wcsncpy(buf, p, n);
938             buf += n;
939             *buf++ = DELIM;
940             if (q == NULL) {
941                 break;
942             }
943             p = q+1;
944         }
945     }
946     if (argv0_path) {
947         wcscpy(buf, argv0_path);
948         buf = wcschr(buf, L'\0');
949         *buf++ = DELIM;
950     }
951     *(buf - 1) = L'\0';
952 
953     /* Now to pull one last hack/trick.  If sys.prefix is
954        empty, then try and find it somewhere on the paths
955        we calculated.  We scan backwards, as our general policy
956        is that Python core directories are at the *end* of
957        sys.path.  We assume that our "lib" directory is
958        on the path, and that our 'prefix' directory is
959        the parent of that.
960     */
961     if (prefix[0] == L'\0') {
962         wchar_t lookBuf[MAXPATHLEN+1];
963         const wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
964         while (1) {
965             Py_ssize_t nchars;
966             const wchar_t *lookEnd = look;
967             /* 'look' will end up one character before the
968                start of the path in question - even if this
969                is one character before the start of the buffer
970             */
971             while (look >= start_buf && *look != DELIM)
972                 look--;
973             nchars = lookEnd-look;
974             wcsncpy(lookBuf, look+1, nchars);
975             lookBuf[nchars] = L'\0';
976             /* Up one level to the parent */
977             reduce(lookBuf);
978             if (search_for_prefix(prefix, lookBuf, LANDMARK)) {
979                 break;
980             }
981             /* If we are out of paths to search - give up */
982             if (look < start_buf) {
983                 break;
984             }
985             look--;
986         }
987     }
988 
989     pathconfig->module_search_path = start_buf;
990     return _PyStatus_OK();
991 }
992 
993 
994 static PyStatus
calculate_path(PyCalculatePath * calculate,_PyPathConfig * pathconfig)995 calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
996 {
997     PyStatus status;
998 
999     status = get_program_full_path(pathconfig);
1000     if (_PyStatus_EXCEPTION(status)) {
1001         return status;
1002     }
1003 
1004     /* program_full_path guaranteed \0 terminated in MAXPATH+1 bytes. */
1005     wchar_t argv0_path[MAXPATHLEN+1];
1006     memset(argv0_path, 0, sizeof(argv0_path));
1007 
1008     wcscpy_s(argv0_path, MAXPATHLEN+1, pathconfig->program_full_path);
1009     reduce(argv0_path);
1010 
1011     wchar_t prefix[MAXPATHLEN+1];
1012     memset(prefix, 0, sizeof(prefix));
1013 
1014     /* Search for a sys.path file */
1015     int pth_found = 0;
1016     status = calculate_pth_file(calculate, pathconfig, prefix, &pth_found);
1017     if (_PyStatus_EXCEPTION(status)) {
1018         return status;
1019     }
1020     if (pth_found) {
1021         goto done;
1022     }
1023 
1024     calculate_pyvenv_file(calculate, argv0_path, Py_ARRAY_LENGTH(argv0_path));
1025 
1026     /* Calculate zip archive path from DLL or exe path */
1027     wchar_t zip_path[MAXPATHLEN+1];
1028     memset(zip_path, 0, sizeof(zip_path));
1029 
1030     if (get_dllpath(zip_path) || change_ext(zip_path, zip_path, L".zip"))
1031     {
1032         if (change_ext(zip_path, pathconfig->program_full_path, L".zip")) {
1033             zip_path[0] = L'\0';
1034         }
1035     }
1036 
1037     calculate_home_prefix(calculate, argv0_path, zip_path, prefix);
1038 
1039     if (pathconfig->module_search_path == NULL) {
1040         status = calculate_module_search_path(calculate, pathconfig,
1041                                               argv0_path, prefix, zip_path);
1042         if (_PyStatus_EXCEPTION(status)) {
1043             return status;
1044         }
1045     }
1046 
1047 done:
1048     if (pathconfig->prefix == NULL) {
1049         pathconfig->prefix = _PyMem_RawWcsdup(prefix);
1050         if (pathconfig->prefix == NULL) {
1051             return _PyStatus_NO_MEMORY();
1052         }
1053     }
1054     if (pathconfig->exec_prefix == NULL) {
1055         pathconfig->exec_prefix = _PyMem_RawWcsdup(prefix);
1056         if (pathconfig->exec_prefix == NULL) {
1057             return _PyStatus_NO_MEMORY();
1058         }
1059     }
1060 
1061     return _PyStatus_OK();
1062 }
1063 
1064 
1065 static PyStatus
calculate_init(PyCalculatePath * calculate,_PyPathConfig * pathconfig,const PyConfig * config)1066 calculate_init(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
1067                const PyConfig *config)
1068 {
1069     calculate->home = pathconfig->home;
1070     calculate->path_env = _wgetenv(L"PATH");
1071 
1072     calculate->pythonpath_env = config->pythonpath_env;
1073 
1074     return _PyStatus_OK();
1075 }
1076 
1077 
1078 static void
calculate_free(PyCalculatePath * calculate)1079 calculate_free(PyCalculatePath *calculate)
1080 {
1081     PyMem_RawFree(calculate->machine_path);
1082     PyMem_RawFree(calculate->user_path);
1083 }
1084 
1085 
1086 /* Calculate the Python path configuration.
1087 
1088    Inputs:
1089 
1090    - PyConfig.pythonpath_env: PYTHONPATH environment variable
1091    - _PyPathConfig.home: Py_SetPythonHome() or PYTHONHOME environment variable
1092    - PATH environment variable
1093    - __PYVENV_LAUNCHER__ environment variable
1094    - GetModuleFileNameW(NULL): fully qualified path of the executable file of
1095      the current process
1096    - ._pth configuration file
1097    - pyvenv.cfg configuration file
1098    - Registry key "Software\Python\PythonCore\X.Y\PythonPath"
1099      of HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE where X.Y is the Python
1100      version.
1101 
1102    Outputs, 'pathconfig' fields:
1103 
1104    - base_executable
1105    - program_full_path
1106    - module_search_path
1107    - prefix
1108    - exec_prefix
1109    - isolated
1110    - site_import
1111 
1112    If a field is already set (non NULL), it is left unchanged. */
1113 PyStatus
_PyPathConfig_Calculate(_PyPathConfig * pathconfig,const PyConfig * config)1114 _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
1115 {
1116     PyStatus status;
1117     PyCalculatePath calculate;
1118     memset(&calculate, 0, sizeof(calculate));
1119 
1120     status = calculate_init(&calculate, pathconfig, config);
1121     if (_PyStatus_EXCEPTION(status)) {
1122         goto done;
1123     }
1124 
1125     status = calculate_path(&calculate, pathconfig);
1126 
1127 done:
1128     calculate_free(&calculate);
1129     return status;
1130 }
1131 
1132 
1133 /* Load python3.dll before loading any extension module that might refer
1134    to it. That way, we can be sure that always the python3.dll corresponding
1135    to this python DLL is loaded, not a python3.dll that might be on the path
1136    by chance.
1137    Return whether the DLL was found.
1138 */
1139 static int python3_checked = 0;
1140 static HANDLE hPython3;
1141 int
_Py_CheckPython3(void)1142 _Py_CheckPython3(void)
1143 {
1144     wchar_t py3path[MAXPATHLEN+1];
1145     if (python3_checked) {
1146         return hPython3 != NULL;
1147     }
1148     python3_checked = 1;
1149 
1150     /* If there is a python3.dll next to the python3y.dll,
1151        use that DLL */
1152     if (!get_dllpath(py3path)) {
1153         reduce(py3path);
1154         join(py3path, PY3_DLLNAME);
1155         hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
1156         if (hPython3 != NULL) {
1157             return 1;
1158         }
1159     }
1160 
1161     /* If we can locate python3.dll in our application dir,
1162        use that DLL */
1163     hPython3 = LoadLibraryExW(PY3_DLLNAME, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
1164     if (hPython3 != NULL) {
1165         return 1;
1166     }
1167 
1168     /* For back-compat, also search {sys.prefix}\DLLs, though
1169        that has not been a normal install layout for a while */
1170     wcscpy(py3path, Py_GetPrefix());
1171     if (py3path[0]) {
1172         join(py3path, L"DLLs\\" PY3_DLLNAME);
1173         hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
1174     }
1175     return hPython3 != NULL;
1176 }
1177