• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     wchar_t *dll_path;
134 
135     const wchar_t *pythonpath_env;
136 } PyCalculatePath;
137 
138 
139 /* determine if "ch" is a separator character */
140 static int
is_sep(wchar_t ch)141 is_sep(wchar_t ch)
142 {
143 #ifdef ALTSEP
144     return ch == SEP || ch == ALTSEP;
145 #else
146     return ch == SEP;
147 #endif
148 }
149 
150 
151 /* assumes 'dir' null terminated in bounds.  Never writes
152    beyond existing terminator. */
153 static void
reduce(wchar_t * dir)154 reduce(wchar_t *dir)
155 {
156     size_t i = wcsnlen_s(dir, MAXPATHLEN+1);
157     if (i >= MAXPATHLEN+1) {
158         Py_FatalError("buffer overflow in getpathp.c's reduce()");
159     }
160 
161     while (i > 0 && !is_sep(dir[i]))
162         --i;
163     dir[i] = '\0';
164 }
165 
166 
167 static int
change_ext(wchar_t * dest,const wchar_t * src,const wchar_t * ext)168 change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
169 {
170     size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
171     size_t i = src_len;
172     if (i >= MAXPATHLEN+1) {
173         Py_FatalError("buffer overflow in getpathp.c's reduce()");
174     }
175 
176     while (i > 0 && src[i] != '.' && !is_sep(src[i]))
177         --i;
178 
179     if (i == 0) {
180         dest[0] = '\0';
181         return -1;
182     }
183 
184     if (is_sep(src[i])) {
185         i = src_len;
186     }
187 
188     if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) ||
189         wcscat_s(dest, MAXPATHLEN+1, ext))
190     {
191         dest[0] = '\0';
192         return -1;
193     }
194 
195     return 0;
196 }
197 
198 
199 static int
exists(const wchar_t * filename)200 exists(const wchar_t *filename)
201 {
202     return GetFileAttributesW(filename) != 0xFFFFFFFF;
203 }
204 
205 
206 /* Is module -- check for .pyc too.
207    Assumes 'filename' MAXPATHLEN+1 bytes long -
208    may extend 'filename' by one character. */
209 static int
ismodule(wchar_t * filename,int update_filename)210 ismodule(wchar_t *filename, int update_filename)
211 {
212     size_t n;
213 
214     if (exists(filename)) {
215         return 1;
216     }
217 
218     /* Check for the compiled version of prefix. */
219     n = wcsnlen_s(filename, MAXPATHLEN+1);
220     if (n < MAXPATHLEN) {
221         int exist = 0;
222         filename[n] = L'c';
223         filename[n + 1] = L'\0';
224         exist = exists(filename);
225         if (!update_filename) {
226             filename[n] = L'\0';
227         }
228         return exist;
229     }
230     return 0;
231 }
232 
233 
234 /* Add a path component, by appending stuff to buffer.
235    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
236    NUL-terminated string with no more than MAXPATHLEN characters (not counting
237    the trailing NUL).  It's a fatal error if it contains a string longer than
238    that (callers must be careful!).  If these requirements are met, it's
239    guaranteed that buffer will still be a NUL-terminated string with no more
240    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
241    stuff as fits will be appended.
242 */
243 
244 static int _PathCchCombineEx_Initialized = 0;
245 typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut,
246                                                PCWSTR pszPathIn, PCWSTR pszMore,
247                                                unsigned long dwFlags);
248 static PPathCchCombineEx _PathCchCombineEx;
249 
250 static void
join(wchar_t * buffer,const wchar_t * stuff)251 join(wchar_t *buffer, const wchar_t *stuff)
252 {
253     if (_PathCchCombineEx_Initialized == 0) {
254         HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
255         if (pathapi) {
256             _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx");
257         }
258         else {
259             _PathCchCombineEx = NULL;
260         }
261         _PathCchCombineEx_Initialized = 1;
262     }
263 
264     if (_PathCchCombineEx) {
265         if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) {
266             Py_FatalError("buffer overflow in getpathp.c's join()");
267         }
268     } else {
269         if (!PathCombineW(buffer, buffer, stuff)) {
270             Py_FatalError("buffer overflow in getpathp.c's join()");
271         }
272     }
273 }
274 
275 static int _PathCchCanonicalizeEx_Initialized = 0;
276 typedef HRESULT(__stdcall *PPathCchCanonicalizeEx) (PWSTR pszPathOut, size_t cchPathOut,
277     PCWSTR pszPathIn, unsigned long dwFlags);
278 static PPathCchCanonicalizeEx _PathCchCanonicalizeEx;
279 
280 /* Call PathCchCanonicalizeEx(path): remove navigation elements such as "."
281    and ".." to produce a direct, well-formed path. */
282 static PyStatus
canonicalize(wchar_t * buffer,const wchar_t * path)283 canonicalize(wchar_t *buffer, const wchar_t *path)
284 {
285     if (buffer == NULL) {
286         return _PyStatus_NO_MEMORY();
287     }
288 
289     if (_PathCchCanonicalizeEx_Initialized == 0) {
290         HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
291         if (pathapi) {
292             _PathCchCanonicalizeEx = (PPathCchCanonicalizeEx)GetProcAddress(pathapi, "PathCchCanonicalizeEx");
293         }
294         else {
295             _PathCchCanonicalizeEx = NULL;
296         }
297         _PathCchCanonicalizeEx_Initialized = 1;
298     }
299 
300     if (_PathCchCanonicalizeEx) {
301         if (FAILED(_PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) {
302             return INIT_ERR_BUFFER_OVERFLOW();
303         }
304     }
305     else {
306         if (!PathCanonicalizeW(buffer, path)) {
307             return INIT_ERR_BUFFER_OVERFLOW();
308         }
309     }
310     return _PyStatus_OK();
311 }
312 
313 
314 /* gotlandmark only called by search_for_prefix, which ensures
315    'prefix' is null terminated in bounds.  join() ensures
316    'landmark' can not overflow prefix if too long. */
317 static int
gotlandmark(const wchar_t * prefix,const wchar_t * landmark)318 gotlandmark(const wchar_t *prefix, const wchar_t *landmark)
319 {
320     wchar_t filename[MAXPATHLEN+1];
321     memset(filename, 0, sizeof(filename));
322     wcscpy_s(filename, Py_ARRAY_LENGTH(filename), prefix);
323     join(filename, landmark);
324     return ismodule(filename, FALSE);
325 }
326 
327 
328 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
329    assumption provided by only caller, calculate_path() */
330 static int
search_for_prefix(wchar_t * prefix,const wchar_t * argv0_path,const wchar_t * landmark)331 search_for_prefix(wchar_t *prefix, const wchar_t *argv0_path, const wchar_t *landmark)
332 {
333     /* Search from argv0_path, until landmark is found */
334     wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
335     do {
336         if (gotlandmark(prefix, landmark)) {
337             return 1;
338         }
339         reduce(prefix);
340     } while (prefix[0]);
341     return 0;
342 }
343 
344 
345 #ifdef Py_ENABLE_SHARED
346 
347 /* a string loaded from the DLL at startup.*/
348 extern const char *PyWin_DLLVersionString;
349 
350 /* Load a PYTHONPATH value from the registry.
351    Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
352 
353    Works in both Unicode and 8bit environments.  Only uses the
354    Ex family of functions so it also works with Windows CE.
355 
356    Returns NULL, or a pointer that should be freed.
357 
358    XXX - this code is pretty strange, as it used to also
359    work on Win16, where the buffer sizes werent available
360    in advance.  It could be simplied now Win16/Win32s is dead!
361 */
362 static wchar_t *
getpythonregpath(HKEY keyBase,int skipcore)363 getpythonregpath(HKEY keyBase, int skipcore)
364 {
365     HKEY newKey = 0;
366     DWORD dataSize = 0;
367     DWORD numKeys = 0;
368     LONG rc;
369     wchar_t *retval = NULL;
370     WCHAR *dataBuf = NULL;
371     static const WCHAR keyPrefix[] = L"Software\\Python\\PythonCore\\";
372     static const WCHAR keySuffix[] = L"\\PythonPath";
373     size_t versionLen, keyBufLen;
374     DWORD index;
375     WCHAR *keyBuf = NULL;
376     WCHAR *keyBufPtr;
377     WCHAR **ppPaths = NULL;
378 
379     /* Tried to use sysget("winver") but here is too early :-( */
380     versionLen = strlen(PyWin_DLLVersionString);
381     /* Space for all the chars, plus one \0 */
382     keyBufLen = sizeof(keyPrefix) +
383                 sizeof(WCHAR)*(versionLen-1) +
384                 sizeof(keySuffix);
385     keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen);
386     if (keyBuf==NULL) {
387         goto done;
388     }
389 
390     memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
391     keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1;
392     mbstowcs(keyBufPtr, PyWin_DLLVersionString, versionLen);
393     keyBufPtr += versionLen;
394     /* NULL comes with this one! */
395     memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
396     /* Open the root Python key */
397     rc=RegOpenKeyExW(keyBase,
398                     keyBuf, /* subkey */
399             0, /* reserved */
400             KEY_READ,
401             &newKey);
402     if (rc!=ERROR_SUCCESS) {
403         goto done;
404     }
405     /* Find out how big our core buffer is, and how many subkeys we have */
406     rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
407                     NULL, NULL, &dataSize, NULL, NULL);
408     if (rc!=ERROR_SUCCESS) {
409         goto done;
410     }
411     if (skipcore) {
412         dataSize = 0; /* Only count core ones if we want them! */
413     }
414     /* Allocate a temp array of char buffers, so we only need to loop
415        reading the registry once
416     */
417     ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys );
418     if (ppPaths==NULL) {
419         goto done;
420     }
421     memset(ppPaths, 0, sizeof(WCHAR *) * numKeys);
422     /* Loop over all subkeys, allocating a temp sub-buffer. */
423     for(index=0;index<numKeys;index++) {
424         WCHAR keyBuf[MAX_PATH+1];
425         HKEY subKey = 0;
426         DWORD reqdSize = MAX_PATH+1;
427         /* Get the sub-key name */
428         DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
429                                  NULL, NULL, NULL, NULL );
430         if (rc!=ERROR_SUCCESS) {
431             goto done;
432         }
433         /* Open the sub-key */
434         rc=RegOpenKeyExW(newKey,
435                                         keyBuf, /* subkey */
436                         0, /* reserved */
437                         KEY_READ,
438                         &subKey);
439         if (rc!=ERROR_SUCCESS) {
440             goto done;
441         }
442         /* Find the value of the buffer size, malloc, then read it */
443         RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
444         if (reqdSize) {
445             ppPaths[index] = PyMem_RawMalloc(reqdSize);
446             if (ppPaths[index]) {
447                 RegQueryValueExW(subKey, NULL, 0, NULL,
448                                 (LPBYTE)ppPaths[index],
449                                 &reqdSize);
450                 dataSize += reqdSize + 1; /* 1 for the ";" */
451             }
452         }
453         RegCloseKey(subKey);
454     }
455 
456     /* return null if no path to return */
457     if (dataSize == 0) {
458         goto done;
459     }
460 
461     /* original datasize from RegQueryInfo doesn't include the \0 */
462     dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
463     if (dataBuf) {
464         WCHAR *szCur = dataBuf;
465         /* Copy our collected strings */
466         for (index=0;index<numKeys;index++) {
467             if (index > 0) {
468                 *(szCur++) = L';';
469                 dataSize--;
470             }
471             if (ppPaths[index]) {
472                 Py_ssize_t len = wcslen(ppPaths[index]);
473                 wcsncpy(szCur, ppPaths[index], len);
474                 szCur += len;
475                 assert(dataSize > (DWORD)len);
476                 dataSize -= (DWORD)len;
477             }
478         }
479         if (skipcore) {
480             *szCur = '\0';
481         }
482         else {
483             /* If we have no values, we don't need a ';' */
484             if (numKeys) {
485                 *(szCur++) = L';';
486                 dataSize--;
487             }
488             /* Now append the core path entries -
489                this will include the NULL
490             */
491             rc = RegQueryValueExW(newKey, NULL, 0, NULL,
492                                   (LPBYTE)szCur, &dataSize);
493             if (rc != ERROR_SUCCESS) {
494                 PyMem_RawFree(dataBuf);
495                 goto done;
496             }
497         }
498         /* And set the result - caller must free */
499         retval = dataBuf;
500     }
501 done:
502     /* Loop freeing my temp buffers */
503     if (ppPaths) {
504         for(index=0; index<numKeys; index++)
505             PyMem_RawFree(ppPaths[index]);
506         PyMem_RawFree(ppPaths);
507     }
508     if (newKey) {
509         RegCloseKey(newKey);
510     }
511     PyMem_RawFree(keyBuf);
512     return retval;
513 }
514 #endif /* Py_ENABLE_SHARED */
515 
516 
517 wchar_t*
_Py_GetDLLPath(void)518 _Py_GetDLLPath(void)
519 {
520     wchar_t dll_path[MAXPATHLEN+1];
521     memset(dll_path, 0, sizeof(dll_path));
522 
523 #ifdef Py_ENABLE_SHARED
524     extern HANDLE PyWin_DLLhModule;
525     if (PyWin_DLLhModule) {
526         if (!GetModuleFileNameW(PyWin_DLLhModule, dll_path, MAXPATHLEN)) {
527             dll_path[0] = 0;
528         }
529     }
530 #else
531     dll_path[0] = 0;
532 #endif
533 
534     return _PyMem_RawWcsdup(dll_path);
535 }
536 
537 
538 static PyStatus
get_program_full_path(_PyPathConfig * pathconfig)539 get_program_full_path(_PyPathConfig *pathconfig)
540 {
541     PyStatus status;
542     const wchar_t *pyvenv_launcher;
543     wchar_t program_full_path[MAXPATHLEN+1];
544     memset(program_full_path, 0, sizeof(program_full_path));
545 
546     if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
547         /* GetModuleFileName should never fail when passed NULL */
548         return _PyStatus_ERR("Cannot determine program path");
549     }
550 
551     /* The launcher may need to force the executable path to a
552      * different environment, so override it here. */
553     pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
554     if (pyvenv_launcher && pyvenv_launcher[0]) {
555         /* If overridden, preserve the original full path */
556         if (pathconfig->base_executable == NULL) {
557             pathconfig->base_executable = PyMem_RawMalloc(
558                 sizeof(wchar_t) * (MAXPATHLEN + 1));
559             if (pathconfig->base_executable == NULL) {
560                 return _PyStatus_NO_MEMORY();
561             }
562 
563             status = canonicalize(pathconfig->base_executable,
564                                   program_full_path);
565             if (_PyStatus_EXCEPTION(status)) {
566                 return status;
567             }
568         }
569 
570         wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
571         /* bpo-35873: Clear the environment variable to avoid it being
572         * inherited by child processes. */
573         _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
574     }
575 
576     if (pathconfig->program_full_path == NULL) {
577         pathconfig->program_full_path = PyMem_RawMalloc(
578             sizeof(wchar_t) * (MAXPATHLEN + 1));
579         if (pathconfig->program_full_path == NULL) {
580             return _PyStatus_NO_MEMORY();
581         }
582 
583         status = canonicalize(pathconfig->program_full_path,
584                               program_full_path);
585         if (_PyStatus_EXCEPTION(status)) {
586             return status;
587         }
588     }
589     return _PyStatus_OK();
590 }
591 
592 
593 static PyStatus
read_pth_file(_PyPathConfig * pathconfig,wchar_t * prefix,const wchar_t * path,int * found)594 read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path,
595               int *found)
596 {
597     PyStatus status;
598     wchar_t *buf = NULL;
599     wchar_t *wline = NULL;
600     FILE *sp_file;
601 
602     sp_file = _Py_wfopen(path, L"r");
603     if (sp_file == NULL) {
604         return _PyStatus_OK();
605     }
606 
607     wcscpy_s(prefix, MAXPATHLEN+1, path);
608     reduce(prefix);
609     pathconfig->isolated = 1;
610     pathconfig->site_import = 0;
611 
612     size_t bufsiz = MAXPATHLEN;
613     size_t prefixlen = wcslen(prefix);
614 
615     buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
616     if (buf == NULL) {
617         status = _PyStatus_NO_MEMORY();
618         goto done;
619     }
620     buf[0] = '\0';
621 
622     while (!feof(sp_file)) {
623         char line[MAXPATHLEN + 1];
624         char *p = fgets(line, Py_ARRAY_LENGTH(line), sp_file);
625         if (!p) {
626             break;
627         }
628         if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') {
629             continue;
630         }
631         while (*++p) {
632             if (*p == '\r' || *p == '\n') {
633                 *p = '\0';
634                 break;
635             }
636         }
637 
638         if (strcmp(line, "import site") == 0) {
639             pathconfig->site_import = 1;
640             continue;
641         }
642         else if (strncmp(line, "import ", 7) == 0) {
643             status = _PyStatus_ERR("only 'import site' is supported "
644                                    "in ._pth file");
645             goto done;
646         }
647 
648         DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
649         wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
650         if (wline == NULL) {
651             status = _PyStatus_NO_MEMORY();
652             goto done;
653         }
654         wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
655         wline[wn] = '\0';
656 
657         size_t usedsiz = wcslen(buf);
658         while (usedsiz + wn + prefixlen + 4 > bufsiz) {
659             bufsiz += MAXPATHLEN;
660             wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
661                                                             sizeof(wchar_t));
662             if (tmp == NULL) {
663                 status = _PyStatus_NO_MEMORY();
664                 goto done;
665             }
666             buf = tmp;
667         }
668 
669         if (usedsiz) {
670             wcscat_s(buf, bufsiz, L";");
671             usedsiz += 1;
672         }
673 
674         errno_t result;
675         _Py_BEGIN_SUPPRESS_IPH
676         result = wcscat_s(buf, bufsiz, prefix);
677         _Py_END_SUPPRESS_IPH
678 
679         if (result == EINVAL) {
680             status = _PyStatus_ERR("invalid argument during ._pth processing");
681             goto done;
682         } else if (result == ERANGE) {
683             status = _PyStatus_ERR("buffer overflow during ._pth processing");
684             goto done;
685         }
686 
687         wchar_t *b = &buf[usedsiz];
688         join(b, wline);
689 
690         PyMem_RawFree(wline);
691         wline = NULL;
692     }
693 
694     if (pathconfig->module_search_path == NULL) {
695         pathconfig->module_search_path = _PyMem_RawWcsdup(buf);
696         if (pathconfig->module_search_path == NULL) {
697             status = _PyStatus_NO_MEMORY();
698             goto done;
699         }
700     }
701 
702     *found = 1;
703     status = _PyStatus_OK();
704     goto done;
705 
706 done:
707     PyMem_RawFree(buf);
708     PyMem_RawFree(wline);
709     fclose(sp_file);
710     return status;
711 }
712 
713 
714 static int
get_pth_filename(PyCalculatePath * calculate,wchar_t * filename,const _PyPathConfig * pathconfig)715 get_pth_filename(PyCalculatePath *calculate, wchar_t *filename,
716                  const _PyPathConfig *pathconfig)
717 {
718     if (calculate->dll_path[0]) {
719         if (!change_ext(filename, calculate->dll_path, L"._pth") &&
720             exists(filename))
721         {
722             return 1;
723         }
724     }
725     if (pathconfig->program_full_path[0]) {
726         if (!change_ext(filename, pathconfig->program_full_path, L"._pth") &&
727             exists(filename))
728         {
729             return 1;
730         }
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     change_ext(zip_path,
1031                calculate->dll_path[0] ? calculate->dll_path : pathconfig->program_full_path,
1032                L".zip");
1033 
1034     calculate_home_prefix(calculate, argv0_path, zip_path, prefix);
1035 
1036     if (pathconfig->module_search_path == NULL) {
1037         status = calculate_module_search_path(calculate, pathconfig,
1038                                               argv0_path, prefix, zip_path);
1039         if (_PyStatus_EXCEPTION(status)) {
1040             return status;
1041         }
1042     }
1043 
1044 done:
1045     if (pathconfig->prefix == NULL) {
1046         pathconfig->prefix = _PyMem_RawWcsdup(prefix);
1047         if (pathconfig->prefix == NULL) {
1048             return _PyStatus_NO_MEMORY();
1049         }
1050     }
1051     if (pathconfig->exec_prefix == NULL) {
1052         pathconfig->exec_prefix = _PyMem_RawWcsdup(prefix);
1053         if (pathconfig->exec_prefix == NULL) {
1054             return _PyStatus_NO_MEMORY();
1055         }
1056     }
1057 
1058     return _PyStatus_OK();
1059 }
1060 
1061 
1062 static PyStatus
calculate_init(PyCalculatePath * calculate,_PyPathConfig * pathconfig,const PyConfig * config)1063 calculate_init(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
1064                const PyConfig *config)
1065 {
1066     calculate->home = pathconfig->home;
1067     calculate->path_env = _wgetenv(L"PATH");
1068 
1069     calculate->dll_path = _Py_GetDLLPath();
1070     if (calculate->dll_path == NULL) {
1071         return _PyStatus_NO_MEMORY();
1072     }
1073 
1074     calculate->pythonpath_env = config->pythonpath_env;
1075 
1076     return _PyStatus_OK();
1077 }
1078 
1079 
1080 static void
calculate_free(PyCalculatePath * calculate)1081 calculate_free(PyCalculatePath *calculate)
1082 {
1083     PyMem_RawFree(calculate->machine_path);
1084     PyMem_RawFree(calculate->user_path);
1085     PyMem_RawFree(calculate->dll_path);
1086 }
1087 
1088 
1089 /* Calculate the Python path configuration.
1090 
1091    Inputs:
1092 
1093    - PyConfig.pythonpath_env: PYTHONPATH environment variable
1094    - _PyPathConfig.home: Py_SetPythonHome() or PYTHONHOME environment variable
1095    - DLL path: _Py_GetDLLPath()
1096    - PATH environment variable
1097    - __PYVENV_LAUNCHER__ environment variable
1098    - GetModuleFileNameW(NULL): fully qualified path of the executable file of
1099      the current process
1100    - ._pth configuration file
1101    - pyvenv.cfg configuration file
1102    - Registry key "Software\Python\PythonCore\X.Y\PythonPath"
1103      of HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE where X.Y is the Python
1104      version.
1105 
1106    Outputs, 'pathconfig' fields:
1107 
1108    - base_executable
1109    - program_full_path
1110    - module_search_path
1111    - prefix
1112    - exec_prefix
1113    - isolated
1114    - site_import
1115 
1116    If a field is already set (non NULL), it is left unchanged. */
1117 PyStatus
_PyPathConfig_Calculate(_PyPathConfig * pathconfig,const PyConfig * config)1118 _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
1119 {
1120     PyStatus status;
1121     PyCalculatePath calculate;
1122     memset(&calculate, 0, sizeof(calculate));
1123 
1124     status = calculate_init(&calculate, pathconfig, config);
1125     if (_PyStatus_EXCEPTION(status)) {
1126         goto done;
1127     }
1128 
1129     status = calculate_path(&calculate, pathconfig);
1130 
1131 done:
1132     calculate_free(&calculate);
1133     return status;
1134 }
1135 
1136 
1137 /* Load python3.dll before loading any extension module that might refer
1138    to it. That way, we can be sure that always the python3.dll corresponding
1139    to this python DLL is loaded, not a python3.dll that might be on the path
1140    by chance.
1141    Return whether the DLL was found.
1142 */
1143 static int python3_checked = 0;
1144 static HANDLE hPython3;
1145 int
_Py_CheckPython3(void)1146 _Py_CheckPython3(void)
1147 {
1148     wchar_t py3path[MAXPATHLEN+1];
1149     wchar_t *s;
1150     if (python3_checked) {
1151         return hPython3 != NULL;
1152     }
1153     python3_checked = 1;
1154 
1155     /* If there is a python3.dll next to the python3y.dll,
1156        assume this is a build tree; use that DLL */
1157     if (_Py_dll_path != NULL) {
1158         wcscpy(py3path, _Py_dll_path);
1159     }
1160     else {
1161         wcscpy(py3path, L"");
1162     }
1163     s = wcsrchr(py3path, L'\\');
1164     if (!s) {
1165         s = py3path;
1166     }
1167     wcscpy(s, L"\\python3.dll");
1168     hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1169     if (hPython3 != NULL) {
1170         return 1;
1171     }
1172 
1173     /* Check sys.prefix\DLLs\python3.dll */
1174     wcscpy(py3path, Py_GetPrefix());
1175     wcscat(py3path, L"\\DLLs\\python3.dll");
1176     hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1177     return hPython3 != NULL;
1178 }
1179