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