1 #include "Python.h"
2 #include "pycore_fileutils.h"     // _Py_HasFileSystemDefaultEncodeErrors
3 #include "pycore_getopt.h"        // _PyOS_GetOpt()
4 #include "pycore_initconfig.h"    // _PyStatus_OK()
5 #include "pycore_interp.h"        // _PyInterpreterState.runtime
6 #include "pycore_pathconfig.h"    // _Py_path_config
7 #include "pycore_pyerrors.h"      // _PyErr_Fetch()
8 #include "pycore_pylifecycle.h"   // _Py_PreInitializeFromConfig()
9 #include "pycore_pymem.h"         // _PyMem_SetDefaultAllocator()
10 #include "pycore_pystate.h"       // _PyThreadState_GET()
11 
12 #include "osdefs.h"               // DELIM
13 #include <locale.h>               // setlocale()
14 #ifdef HAVE_LANGINFO_H
15 #  include <langinfo.h>           // nl_langinfo(CODESET)
16 #endif
17 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
18 #  include <windows.h>            // GetACP()
19 #  ifdef HAVE_IO_H
20 #    include <io.h>
21 #  endif
22 #  ifdef HAVE_FCNTL_H
23 #    include <fcntl.h>            // O_BINARY
24 #  endif
25 #endif
26 
27 #ifndef PLATLIBDIR
28 #  error "PLATLIBDIR macro must be defined"
29 #endif
30 
31 
32 /* --- Command line options --------------------------------------- */
33 
34 /* Short usage message (with %s for argv0) */
35 static const char usage_line[] =
36 "usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
37 
38 /* Long usage message, split into parts < 512 bytes */
39 static const char usage_1[] = "\
40 Options and arguments (and corresponding environment variables):\n\
41 -b     : issue warnings about str(bytes_instance), str(bytearray_instance)\n\
42          and comparing bytes/bytearray with str. (-bb: issue errors)\n\
43 -B     : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\
44 -c cmd : program passed in as string (terminates option list)\n\
45 -d     : turn on parser debugging output (for experts only, only works on\n\
46          debug builds); also PYTHONDEBUG=x\n\
47 -E     : ignore PYTHON* environment variables (such as PYTHONPATH)\n\
48 -h     : print this help message and exit (also --help)\n\
49 ";
50 static const char usage_2[] = "\
51 -i     : inspect interactively after running script; forces a prompt even\n\
52          if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\
53 -I     : isolate Python from the user's environment (implies -E and -s)\n\
54 -m mod : run library module as a script (terminates option list)\n\
55 -O     : remove assert and __debug__-dependent statements; add .opt-1 before\n\
56          .pyc extension; also PYTHONOPTIMIZE=x\n\
57 -OO    : do -O changes and also discard docstrings; add .opt-2 before\n\
58          .pyc extension\n\
59 -q     : don't print version and copyright messages on interactive startup\n\
60 -s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
61 -S     : don't imply 'import site' on initialization\n\
62 ";
63 static const char usage_3[] = "\
64 -u     : force the stdout and stderr streams to be unbuffered;\n\
65          this option has no effect on stdin; also PYTHONUNBUFFERED=x\n\
66 -v     : verbose (trace import statements); also PYTHONVERBOSE=x\n\
67          can be supplied multiple times to increase verbosity\n\
68 -V     : print the Python version number and exit (also --version)\n\
69          when given twice, print more information about the build\n\
70 -W arg : warning control; arg is action:message:category:module:lineno\n\
71          also PYTHONWARNINGS=arg\n\
72 -x     : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
73 -X opt : set implementation-specific option. The following options are available:\n\
74 \n\
75          -X faulthandler: enable faulthandler\n\
76          -X oldparser: enable the traditional LL(1) parser; also PYTHONOLDPARSER\n\
77          -X showrefcount: output the total reference count and number of used\n\
78              memory blocks when the program finishes or after each statement in the\n\
79              interactive interpreter. This only works on debug builds\n\
80          -X tracemalloc: start tracing Python memory allocations using the\n\
81              tracemalloc module. By default, only the most recent frame is stored in a\n\
82              traceback of a trace. Use -X tracemalloc=NFRAME to start tracing with a\n\
83              traceback limit of NFRAME frames\n\
84          -X importtime: show how long each import takes. It shows module name,\n\
85              cumulative time (including nested imports) and self time (excluding\n\
86              nested imports). Note that its output may be broken in multi-threaded\n\
87              application. Typical usage is python3 -X importtime -c 'import asyncio'\n\
88          -X dev: enable CPython's \"development mode\", introducing additional runtime\n\
89              checks which are too expensive to be enabled by default. Effect of the\n\
90              developer mode:\n\
91                 * Add default warning filter, as -W default\n\
92                 * Install debug hooks on memory allocators: see the PyMem_SetupDebugHooks() C function\n\
93                 * Enable the faulthandler module to dump the Python traceback on a crash\n\
94                 * Enable asyncio debug mode\n\
95                 * Set the dev_mode attribute of sys.flags to True\n\
96                 * io.IOBase destructor logs close() exceptions\n\
97          -X utf8: enable UTF-8 mode for operating system interfaces, overriding the default\n\
98              locale-aware mode. -X utf8=0 explicitly disables UTF-8 mode (even when it would\n\
99              otherwise activate automatically)\n\
100          -X pycache_prefix=PATH: enable writing .pyc files to a parallel tree rooted at the\n\
101              given directory instead of to the code tree\n\
102 \n\
103 --check-hash-based-pycs always|default|never:\n\
104     control how Python invalidates hash-based .pyc files\n\
105 ";
106 static const char usage_4[] = "\
107 file   : program read from script file\n\
108 -      : program read from stdin (default; interactive mode if a tty)\n\
109 arg ...: arguments passed to program in sys.argv[1:]\n\n\
110 Other environment variables:\n\
111 PYTHONSTARTUP: file executed on interactive startup (no default)\n\
112 PYTHONPATH   : '%lc'-separated list of directories prefixed to the\n\
113                default module search path.  The result is sys.path.\n\
114 ";
115 static const char usage_5[] =
116 "PYTHONHOME   : alternate <prefix> directory (or <prefix>%lc<exec_prefix>).\n"
117 "               The default module search path uses %s.\n"
118 "PYTHONPLATLIBDIR : override sys.platlibdir.\n"
119 "PYTHONCASEOK : ignore case in 'import' statements (Windows).\n"
120 "PYTHONUTF8: if set to 1, enable the UTF-8 mode.\n"
121 "PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n"
122 "PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n";
123 static const char usage_6[] =
124 "PYTHONHASHSEED: if this variable is set to 'random', a random value is used\n"
125 "   to seed the hashes of str and bytes objects.  It can also be set to an\n"
126 "   integer in the range [0,4294967295] to get hash values with a\n"
127 "   predictable seed.\n"
128 "PYTHONMALLOC: set the Python memory allocators and/or install debug hooks\n"
129 "   on Python memory allocators. Use PYTHONMALLOC=debug to install debug\n"
130 "   hooks.\n"
131 "PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n"
132 "   coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of\n"
133 "   locale coercion and locale compatibility warnings on stderr.\n"
134 "PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
135 "   debugger. It can be set to the callable of your debugger of choice.\n"
136 "PYTHONDEVMODE: enable the development mode.\n"
137 "PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n";
138 
139 #if defined(MS_WINDOWS)
140 #  define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
141 #else
142 #  define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
143 #endif
144 
145 
146 /* --- Global configuration variables ----------------------------- */
147 
148 /* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change
149    stdin and stdout error handler to "surrogateescape". */
150 int Py_UTF8Mode = 0;
151 int Py_DebugFlag = 0; /* Needed by parser.c */
152 int Py_VerboseFlag = 0; /* Needed by import.c */
153 int Py_QuietFlag = 0; /* Needed by sysmodule.c */
154 int Py_InteractiveFlag = 0; /* Needed by Py_FdIsInteractive() below */
155 int Py_InspectFlag = 0; /* Needed to determine whether to exit at SystemExit */
156 int Py_OptimizeFlag = 0; /* Needed by compile.c */
157 int Py_NoSiteFlag = 0; /* Suppress 'import site' */
158 int Py_BytesWarningFlag = 0; /* Warn on str(bytes) and str(buffer) */
159 int Py_FrozenFlag = 0; /* Needed by getpath.c */
160 int Py_IgnoreEnvironmentFlag = 0; /* e.g. PYTHONPATH, PYTHONHOME */
161 int Py_DontWriteBytecodeFlag = 0; /* Suppress writing bytecode files (*.pyc) */
162 int Py_NoUserSiteDirectory = 0; /* for -s and site.py */
163 int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */
164 int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */
165 int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */
166 #ifdef MS_WINDOWS
167 int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */
168 int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */
169 #endif
170 
171 
172 static PyObject *
_Py_GetGlobalVariablesAsDict(void)173 _Py_GetGlobalVariablesAsDict(void)
174 {
175     PyObject *dict, *obj;
176 
177     dict = PyDict_New();
178     if (dict == NULL) {
179         return NULL;
180     }
181 
182 #define SET_ITEM(KEY, EXPR) \
183         do { \
184             obj = (EXPR); \
185             if (obj == NULL) { \
186                 return NULL; \
187             } \
188             int res = PyDict_SetItemString(dict, (KEY), obj); \
189             Py_DECREF(obj); \
190             if (res < 0) { \
191                 goto fail; \
192             } \
193         } while (0)
194 #define SET_ITEM_INT(VAR) \
195     SET_ITEM(#VAR, PyLong_FromLong(VAR))
196 #define FROM_STRING(STR) \
197     ((STR != NULL) ? \
198         PyUnicode_FromString(STR) \
199         : (Py_INCREF(Py_None), Py_None))
200 #define SET_ITEM_STR(VAR) \
201     SET_ITEM(#VAR, FROM_STRING(VAR))
202 
203     SET_ITEM_STR(Py_FileSystemDefaultEncoding);
204     SET_ITEM_INT(Py_HasFileSystemDefaultEncoding);
205     SET_ITEM_STR(Py_FileSystemDefaultEncodeErrors);
206     SET_ITEM_INT(_Py_HasFileSystemDefaultEncodeErrors);
207 
208     SET_ITEM_INT(Py_UTF8Mode);
209     SET_ITEM_INT(Py_DebugFlag);
210     SET_ITEM_INT(Py_VerboseFlag);
211     SET_ITEM_INT(Py_QuietFlag);
212     SET_ITEM_INT(Py_InteractiveFlag);
213     SET_ITEM_INT(Py_InspectFlag);
214 
215     SET_ITEM_INT(Py_OptimizeFlag);
216     SET_ITEM_INT(Py_NoSiteFlag);
217     SET_ITEM_INT(Py_BytesWarningFlag);
218     SET_ITEM_INT(Py_FrozenFlag);
219     SET_ITEM_INT(Py_IgnoreEnvironmentFlag);
220     SET_ITEM_INT(Py_DontWriteBytecodeFlag);
221     SET_ITEM_INT(Py_NoUserSiteDirectory);
222     SET_ITEM_INT(Py_UnbufferedStdioFlag);
223     SET_ITEM_INT(Py_HashRandomizationFlag);
224     SET_ITEM_INT(Py_IsolatedFlag);
225 
226 #ifdef MS_WINDOWS
227     SET_ITEM_INT(Py_LegacyWindowsFSEncodingFlag);
228     SET_ITEM_INT(Py_LegacyWindowsStdioFlag);
229 #endif
230 
231     return dict;
232 
233 fail:
234     Py_DECREF(dict);
235     return NULL;
236 
237 #undef FROM_STRING
238 #undef SET_ITEM
239 #undef SET_ITEM_INT
240 #undef SET_ITEM_STR
241 }
242 
243 
244 /* --- PyStatus ----------------------------------------------- */
245 
PyStatus_Ok(void)246 PyStatus PyStatus_Ok(void)
247 { return _PyStatus_OK(); }
248 
PyStatus_Error(const char * err_msg)249 PyStatus PyStatus_Error(const char *err_msg)
250 {
251     return (PyStatus){._type = _PyStatus_TYPE_ERROR,
252                           .err_msg = err_msg};
253 }
254 
PyStatus_NoMemory(void)255 PyStatus PyStatus_NoMemory(void)
256 { return PyStatus_Error("memory allocation failed"); }
257 
PyStatus_Exit(int exitcode)258 PyStatus PyStatus_Exit(int exitcode)
259 { return _PyStatus_EXIT(exitcode); }
260 
261 
PyStatus_IsError(PyStatus status)262 int PyStatus_IsError(PyStatus status)
263 { return _PyStatus_IS_ERROR(status); }
264 
PyStatus_IsExit(PyStatus status)265 int PyStatus_IsExit(PyStatus status)
266 { return _PyStatus_IS_EXIT(status); }
267 
PyStatus_Exception(PyStatus status)268 int PyStatus_Exception(PyStatus status)
269 { return _PyStatus_EXCEPTION(status); }
270 
271 
272 /* --- PyWideStringList ------------------------------------------------ */
273 
274 #ifndef NDEBUG
275 int
_PyWideStringList_CheckConsistency(const PyWideStringList * list)276 _PyWideStringList_CheckConsistency(const PyWideStringList *list)
277 {
278     assert(list->length >= 0);
279     if (list->length != 0) {
280         assert(list->items != NULL);
281     }
282     for (Py_ssize_t i = 0; i < list->length; i++) {
283         assert(list->items[i] != NULL);
284     }
285     return 1;
286 }
287 #endif   /* Py_DEBUG */
288 
289 
290 void
_PyWideStringList_Clear(PyWideStringList * list)291 _PyWideStringList_Clear(PyWideStringList *list)
292 {
293     assert(_PyWideStringList_CheckConsistency(list));
294     for (Py_ssize_t i=0; i < list->length; i++) {
295         PyMem_RawFree(list->items[i]);
296     }
297     PyMem_RawFree(list->items);
298     list->length = 0;
299     list->items = NULL;
300 }
301 
302 
303 int
_PyWideStringList_Copy(PyWideStringList * list,const PyWideStringList * list2)304 _PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2)
305 {
306     assert(_PyWideStringList_CheckConsistency(list));
307     assert(_PyWideStringList_CheckConsistency(list2));
308 
309     if (list2->length == 0) {
310         _PyWideStringList_Clear(list);
311         return 0;
312     }
313 
314     PyWideStringList copy = _PyWideStringList_INIT;
315 
316     size_t size = list2->length * sizeof(list2->items[0]);
317     copy.items = PyMem_RawMalloc(size);
318     if (copy.items == NULL) {
319         return -1;
320     }
321 
322     for (Py_ssize_t i=0; i < list2->length; i++) {
323         wchar_t *item = _PyMem_RawWcsdup(list2->items[i]);
324         if (item == NULL) {
325             _PyWideStringList_Clear(&copy);
326             return -1;
327         }
328         copy.items[i] = item;
329         copy.length = i + 1;
330     }
331 
332     _PyWideStringList_Clear(list);
333     *list = copy;
334     return 0;
335 }
336 
337 
338 PyStatus
PyWideStringList_Insert(PyWideStringList * list,Py_ssize_t index,const wchar_t * item)339 PyWideStringList_Insert(PyWideStringList *list,
340                         Py_ssize_t index, const wchar_t *item)
341 {
342     Py_ssize_t len = list->length;
343     if (len == PY_SSIZE_T_MAX) {
344         /* length+1 would overflow */
345         return _PyStatus_NO_MEMORY();
346     }
347     if (index < 0) {
348         return _PyStatus_ERR("PyWideStringList_Insert index must be >= 0");
349     }
350     if (index > len) {
351         index = len;
352     }
353 
354     wchar_t *item2 = _PyMem_RawWcsdup(item);
355     if (item2 == NULL) {
356         return _PyStatus_NO_MEMORY();
357     }
358 
359     size_t size = (len + 1) * sizeof(list->items[0]);
360     wchar_t **items2 = (wchar_t **)PyMem_RawRealloc(list->items, size);
361     if (items2 == NULL) {
362         PyMem_RawFree(item2);
363         return _PyStatus_NO_MEMORY();
364     }
365 
366     if (index < len) {
367         memmove(&items2[index + 1],
368                 &items2[index],
369                 (len - index) * sizeof(items2[0]));
370     }
371 
372     items2[index] = item2;
373     list->items = items2;
374     list->length++;
375     return _PyStatus_OK();
376 }
377 
378 
379 PyStatus
PyWideStringList_Append(PyWideStringList * list,const wchar_t * item)380 PyWideStringList_Append(PyWideStringList *list, const wchar_t *item)
381 {
382     return PyWideStringList_Insert(list, list->length, item);
383 }
384 
385 
386 PyStatus
_PyWideStringList_Extend(PyWideStringList * list,const PyWideStringList * list2)387 _PyWideStringList_Extend(PyWideStringList *list, const PyWideStringList *list2)
388 {
389     for (Py_ssize_t i = 0; i < list2->length; i++) {
390         PyStatus status = PyWideStringList_Append(list, list2->items[i]);
391         if (_PyStatus_EXCEPTION(status)) {
392             return status;
393         }
394     }
395     return _PyStatus_OK();
396 }
397 
398 
399 static int
_PyWideStringList_Find(PyWideStringList * list,const wchar_t * item)400 _PyWideStringList_Find(PyWideStringList *list, const wchar_t *item)
401 {
402     for (Py_ssize_t i = 0; i < list->length; i++) {
403         if (wcscmp(list->items[i], item) == 0) {
404             return 1;
405         }
406     }
407     return 0;
408 }
409 
410 
411 PyObject*
_PyWideStringList_AsList(const PyWideStringList * list)412 _PyWideStringList_AsList(const PyWideStringList *list)
413 {
414     assert(_PyWideStringList_CheckConsistency(list));
415 
416     PyObject *pylist = PyList_New(list->length);
417     if (pylist == NULL) {
418         return NULL;
419     }
420 
421     for (Py_ssize_t i = 0; i < list->length; i++) {
422         PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
423         if (item == NULL) {
424             Py_DECREF(pylist);
425             return NULL;
426         }
427         PyList_SET_ITEM(pylist, i, item);
428     }
429     return pylist;
430 }
431 
432 
433 /* --- Py_SetStandardStreamEncoding() ----------------------------- */
434 
435 /* Helper to allow an embedding application to override the normal
436  * mechanism that attempts to figure out an appropriate IO encoding
437  */
438 
439 static char *_Py_StandardStreamEncoding = NULL;
440 static char *_Py_StandardStreamErrors = NULL;
441 
442 int
Py_SetStandardStreamEncoding(const char * encoding,const char * errors)443 Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
444 {
445     if (Py_IsInitialized()) {
446         /* This is too late to have any effect */
447         return -1;
448     }
449 
450     int res = 0;
451 
452     /* Py_SetStandardStreamEncoding() can be called before Py_Initialize(),
453        but Py_Initialize() can change the allocator. Use a known allocator
454        to be able to release the memory later. */
455     PyMemAllocatorEx old_alloc;
456     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
457 
458     /* Can't call PyErr_NoMemory() on errors, as Python hasn't been
459      * initialised yet.
460      *
461      * However, the raw memory allocators are initialised appropriately
462      * as C static variables, so _PyMem_RawStrdup is OK even though
463      * Py_Initialize hasn't been called yet.
464      */
465     if (encoding) {
466         PyMem_RawFree(_Py_StandardStreamEncoding);
467         _Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding);
468         if (!_Py_StandardStreamEncoding) {
469             res = -2;
470             goto done;
471         }
472     }
473     if (errors) {
474         PyMem_RawFree(_Py_StandardStreamErrors);
475         _Py_StandardStreamErrors = _PyMem_RawStrdup(errors);
476         if (!_Py_StandardStreamErrors) {
477             PyMem_RawFree(_Py_StandardStreamEncoding);
478             _Py_StandardStreamEncoding = NULL;
479             res = -3;
480             goto done;
481         }
482     }
483 #ifdef MS_WINDOWS
484     if (_Py_StandardStreamEncoding) {
485         /* Overriding the stream encoding implies legacy streams */
486         Py_LegacyWindowsStdioFlag = 1;
487     }
488 #endif
489 
490 done:
491     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
492 
493     return res;
494 }
495 
496 
497 void
_Py_ClearStandardStreamEncoding(void)498 _Py_ClearStandardStreamEncoding(void)
499 {
500     /* Use the same allocator than Py_SetStandardStreamEncoding() */
501     PyMemAllocatorEx old_alloc;
502     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
503 
504     /* We won't need them anymore. */
505     if (_Py_StandardStreamEncoding) {
506         PyMem_RawFree(_Py_StandardStreamEncoding);
507         _Py_StandardStreamEncoding = NULL;
508     }
509     if (_Py_StandardStreamErrors) {
510         PyMem_RawFree(_Py_StandardStreamErrors);
511         _Py_StandardStreamErrors = NULL;
512     }
513 
514     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
515 }
516 
517 
518 /* --- Py_GetArgcArgv() ------------------------------------------- */
519 
520 /* For Py_GetArgcArgv(); set by _Py_SetArgcArgv() */
521 static PyWideStringList orig_argv = {.length = 0, .items = NULL};
522 
523 
524 void
_Py_ClearArgcArgv(void)525 _Py_ClearArgcArgv(void)
526 {
527     PyMemAllocatorEx old_alloc;
528     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
529 
530     _PyWideStringList_Clear(&orig_argv);
531 
532     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
533 }
534 
535 
536 static int
_Py_SetArgcArgv(Py_ssize_t argc,wchar_t * const * argv)537 _Py_SetArgcArgv(Py_ssize_t argc, wchar_t * const *argv)
538 {
539     const PyWideStringList argv_list = {.length = argc, .items = (wchar_t **)argv};
540     int res;
541 
542     PyMemAllocatorEx old_alloc;
543     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
544 
545     res = _PyWideStringList_Copy(&orig_argv, &argv_list);
546 
547     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
548     return res;
549 }
550 
551 
552 void
Py_GetArgcArgv(int * argc,wchar_t *** argv)553 Py_GetArgcArgv(int *argc, wchar_t ***argv)
554 {
555     *argc = (int)orig_argv.length;
556     *argv = orig_argv.items;
557 }
558 
559 
560 /* --- PyConfig ---------------------------------------------- */
561 
562 #define DECODE_LOCALE_ERR(NAME, LEN) \
563     (((LEN) == -2) \
564      ? _PyStatus_ERR("cannot decode " NAME) \
565      : _PyStatus_NO_MEMORY())
566 
567 
568 /* Free memory allocated in config, but don't clear all attributes */
569 void
PyConfig_Clear(PyConfig * config)570 PyConfig_Clear(PyConfig *config)
571 {
572 #define CLEAR(ATTR) \
573     do { \
574         PyMem_RawFree(ATTR); \
575         ATTR = NULL; \
576     } while (0)
577 
578     CLEAR(config->pycache_prefix);
579     CLEAR(config->pythonpath_env);
580     CLEAR(config->home);
581     CLEAR(config->program_name);
582 
583     _PyWideStringList_Clear(&config->argv);
584     _PyWideStringList_Clear(&config->warnoptions);
585     _PyWideStringList_Clear(&config->xoptions);
586     _PyWideStringList_Clear(&config->module_search_paths);
587     config->module_search_paths_set = 0;
588 
589     CLEAR(config->executable);
590     CLEAR(config->base_executable);
591     CLEAR(config->prefix);
592     CLEAR(config->base_prefix);
593     CLEAR(config->exec_prefix);
594     CLEAR(config->base_exec_prefix);
595     CLEAR(config->platlibdir);
596 
597     CLEAR(config->filesystem_encoding);
598     CLEAR(config->filesystem_errors);
599     CLEAR(config->stdio_encoding);
600     CLEAR(config->stdio_errors);
601     CLEAR(config->run_command);
602     CLEAR(config->run_module);
603     CLEAR(config->run_filename);
604     CLEAR(config->check_hash_pycs_mode);
605 
606     _PyWideStringList_Clear(&config->_orig_argv);
607 #undef CLEAR
608 }
609 
610 
611 void
_PyConfig_InitCompatConfig(PyConfig * config)612 _PyConfig_InitCompatConfig(PyConfig *config)
613 {
614     memset(config, 0, sizeof(*config));
615 
616     config->_config_init = (int)_PyConfig_INIT_COMPAT;
617     config->isolated = -1;
618     config->use_environment = -1;
619     config->dev_mode = -1;
620     config->install_signal_handlers = 1;
621     config->use_hash_seed = -1;
622     config->faulthandler = -1;
623     config->tracemalloc = -1;
624     config->module_search_paths_set = 0;
625     config->parse_argv = 0;
626     config->site_import = -1;
627     config->bytes_warning = -1;
628     config->inspect = -1;
629     config->interactive = -1;
630     config->optimization_level = -1;
631     config->parser_debug= -1;
632     config->write_bytecode = -1;
633     config->verbose = -1;
634     config->quiet = -1;
635     config->user_site_directory = -1;
636     config->configure_c_stdio = 0;
637     config->buffered_stdio = -1;
638     config->_install_importlib = 1;
639     config->check_hash_pycs_mode = NULL;
640     config->pathconfig_warnings = -1;
641     config->_init_main = 1;
642     config->_isolated_interpreter = 0;
643 #ifdef MS_WINDOWS
644     config->legacy_windows_stdio = -1;
645 #endif
646     config->_use_peg_parser = 1;
647 }
648 
649 
650 static void
config_init_defaults(PyConfig * config)651 config_init_defaults(PyConfig *config)
652 {
653     _PyConfig_InitCompatConfig(config);
654 
655     config->isolated = 0;
656     config->use_environment = 1;
657     config->site_import = 1;
658     config->bytes_warning = 0;
659     config->inspect = 0;
660     config->interactive = 0;
661     config->optimization_level = 0;
662     config->parser_debug= 0;
663     config->write_bytecode = 1;
664     config->verbose = 0;
665     config->quiet = 0;
666     config->user_site_directory = 1;
667     config->buffered_stdio = 1;
668     config->pathconfig_warnings = 1;
669 #ifdef MS_WINDOWS
670     config->legacy_windows_stdio = 0;
671 #endif
672 }
673 
674 
675 void
PyConfig_InitPythonConfig(PyConfig * config)676 PyConfig_InitPythonConfig(PyConfig *config)
677 {
678     config_init_defaults(config);
679 
680     config->_config_init = (int)_PyConfig_INIT_PYTHON;
681     config->configure_c_stdio = 1;
682     config->parse_argv = 1;
683 }
684 
685 
686 void
PyConfig_InitIsolatedConfig(PyConfig * config)687 PyConfig_InitIsolatedConfig(PyConfig *config)
688 {
689     config_init_defaults(config);
690 
691     config->_config_init = (int)_PyConfig_INIT_ISOLATED;
692     config->isolated = 1;
693     config->use_environment = 0;
694     config->user_site_directory = 0;
695     config->dev_mode = 0;
696     config->install_signal_handlers = 0;
697     config->use_hash_seed = 0;
698     config->faulthandler = 0;
699     config->tracemalloc = 0;
700     config->pathconfig_warnings = 0;
701 #ifdef MS_WINDOWS
702     config->legacy_windows_stdio = 0;
703 #endif
704 }
705 
706 
707 /* Copy str into *config_str (duplicate the string) */
708 PyStatus
PyConfig_SetString(PyConfig * config,wchar_t ** config_str,const wchar_t * str)709 PyConfig_SetString(PyConfig *config, wchar_t **config_str, const wchar_t *str)
710 {
711     PyStatus status = _Py_PreInitializeFromConfig(config, NULL);
712     if (_PyStatus_EXCEPTION(status)) {
713         return status;
714     }
715 
716     wchar_t *str2;
717     if (str != NULL) {
718         str2 = _PyMem_RawWcsdup(str);
719         if (str2 == NULL) {
720             return _PyStatus_NO_MEMORY();
721         }
722     }
723     else {
724         str2 = NULL;
725     }
726     PyMem_RawFree(*config_str);
727     *config_str = str2;
728     return _PyStatus_OK();
729 }
730 
731 
732 static PyStatus
config_set_bytes_string(PyConfig * config,wchar_t ** config_str,const char * str,const char * decode_err_msg)733 config_set_bytes_string(PyConfig *config, wchar_t **config_str,
734                         const char *str, const char *decode_err_msg)
735 {
736     PyStatus status = _Py_PreInitializeFromConfig(config, NULL);
737     if (_PyStatus_EXCEPTION(status)) {
738         return status;
739     }
740 
741     wchar_t *str2;
742     if (str != NULL) {
743         size_t len;
744         str2 = Py_DecodeLocale(str, &len);
745         if (str2 == NULL) {
746             if (len == (size_t)-2) {
747                 return _PyStatus_ERR(decode_err_msg);
748             }
749             else {
750                 return  _PyStatus_NO_MEMORY();
751             }
752         }
753     }
754     else {
755         str2 = NULL;
756     }
757     PyMem_RawFree(*config_str);
758     *config_str = str2;
759     return _PyStatus_OK();
760 }
761 
762 
763 #define CONFIG_SET_BYTES_STR(config, config_str, str, NAME) \
764     config_set_bytes_string(config, config_str, str, "cannot decode " NAME)
765 
766 
767 /* Decode str using Py_DecodeLocale() and set the result into *config_str.
768    Pre-initialize Python if needed to ensure that encodings are properly
769    configured. */
770 PyStatus
PyConfig_SetBytesString(PyConfig * config,wchar_t ** config_str,const char * str)771 PyConfig_SetBytesString(PyConfig *config, wchar_t **config_str,
772                            const char *str)
773 {
774     return CONFIG_SET_BYTES_STR(config, config_str, str, "string");
775 }
776 
777 
778 PyStatus
_PyConfig_Copy(PyConfig * config,const PyConfig * config2)779 _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
780 {
781     PyStatus status;
782 
783     PyConfig_Clear(config);
784 
785 #define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
786 #define COPY_WSTR_ATTR(ATTR) \
787     do { \
788         status = PyConfig_SetString(config, &config->ATTR, config2->ATTR); \
789         if (_PyStatus_EXCEPTION(status)) { \
790             return status; \
791         } \
792     } while (0)
793 #define COPY_WSTRLIST(LIST) \
794     do { \
795         if (_PyWideStringList_Copy(&config->LIST, &config2->LIST) < 0) { \
796             return _PyStatus_NO_MEMORY(); \
797         } \
798     } while (0)
799 
800     COPY_ATTR(_config_init);
801     COPY_ATTR(isolated);
802     COPY_ATTR(use_environment);
803     COPY_ATTR(dev_mode);
804     COPY_ATTR(_use_peg_parser);
805     COPY_ATTR(install_signal_handlers);
806     COPY_ATTR(use_hash_seed);
807     COPY_ATTR(hash_seed);
808     COPY_ATTR(_install_importlib);
809     COPY_ATTR(faulthandler);
810     COPY_ATTR(tracemalloc);
811     COPY_ATTR(import_time);
812     COPY_ATTR(show_ref_count);
813     COPY_ATTR(dump_refs);
814     COPY_ATTR(malloc_stats);
815 
816     COPY_WSTR_ATTR(pycache_prefix);
817     COPY_WSTR_ATTR(pythonpath_env);
818     COPY_WSTR_ATTR(home);
819     COPY_WSTR_ATTR(program_name);
820 
821     COPY_ATTR(parse_argv);
822     COPY_WSTRLIST(argv);
823     COPY_WSTRLIST(warnoptions);
824     COPY_WSTRLIST(xoptions);
825     COPY_WSTRLIST(module_search_paths);
826     COPY_ATTR(module_search_paths_set);
827 
828     COPY_WSTR_ATTR(executable);
829     COPY_WSTR_ATTR(base_executable);
830     COPY_WSTR_ATTR(prefix);
831     COPY_WSTR_ATTR(base_prefix);
832     COPY_WSTR_ATTR(exec_prefix);
833     COPY_WSTR_ATTR(base_exec_prefix);
834     COPY_WSTR_ATTR(platlibdir);
835 
836     COPY_ATTR(site_import);
837     COPY_ATTR(bytes_warning);
838     COPY_ATTR(inspect);
839     COPY_ATTR(interactive);
840     COPY_ATTR(optimization_level);
841     COPY_ATTR(parser_debug);
842     COPY_ATTR(write_bytecode);
843     COPY_ATTR(verbose);
844     COPY_ATTR(quiet);
845     COPY_ATTR(user_site_directory);
846     COPY_ATTR(configure_c_stdio);
847     COPY_ATTR(buffered_stdio);
848     COPY_WSTR_ATTR(filesystem_encoding);
849     COPY_WSTR_ATTR(filesystem_errors);
850     COPY_WSTR_ATTR(stdio_encoding);
851     COPY_WSTR_ATTR(stdio_errors);
852 #ifdef MS_WINDOWS
853     COPY_ATTR(legacy_windows_stdio);
854 #endif
855     COPY_ATTR(skip_source_first_line);
856     COPY_WSTR_ATTR(run_command);
857     COPY_WSTR_ATTR(run_module);
858     COPY_WSTR_ATTR(run_filename);
859     COPY_WSTR_ATTR(check_hash_pycs_mode);
860     COPY_ATTR(pathconfig_warnings);
861     COPY_ATTR(_init_main);
862     COPY_ATTR(_isolated_interpreter);
863     COPY_WSTRLIST(_orig_argv);
864 
865 #undef COPY_ATTR
866 #undef COPY_WSTR_ATTR
867 #undef COPY_WSTRLIST
868     return _PyStatus_OK();
869 }
870 
871 
872 static PyObject *
config_as_dict(const PyConfig * config)873 config_as_dict(const PyConfig *config)
874 {
875     PyObject *dict;
876 
877     dict = PyDict_New();
878     if (dict == NULL) {
879         return NULL;
880     }
881 
882 #define SET_ITEM(KEY, EXPR) \
883         do { \
884             PyObject *obj = (EXPR); \
885             if (obj == NULL) { \
886                 goto fail; \
887             } \
888             int res = PyDict_SetItemString(dict, (KEY), obj); \
889             Py_DECREF(obj); \
890             if (res < 0) { \
891                 goto fail; \
892             } \
893         } while (0)
894 #define SET_ITEM_INT(ATTR) \
895     SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
896 #define SET_ITEM_UINT(ATTR) \
897     SET_ITEM(#ATTR, PyLong_FromUnsignedLong(config->ATTR))
898 #define FROM_WSTRING(STR) \
899     ((STR != NULL) ? \
900         PyUnicode_FromWideChar(STR, -1) \
901         : (Py_INCREF(Py_None), Py_None))
902 #define SET_ITEM_WSTR(ATTR) \
903     SET_ITEM(#ATTR, FROM_WSTRING(config->ATTR))
904 #define SET_ITEM_WSTRLIST(LIST) \
905     SET_ITEM(#LIST, _PyWideStringList_AsList(&config->LIST))
906 
907     SET_ITEM_INT(_config_init);
908     SET_ITEM_INT(isolated);
909     SET_ITEM_INT(use_environment);
910     SET_ITEM_INT(dev_mode);
911     SET_ITEM_INT(_use_peg_parser);
912     SET_ITEM_INT(install_signal_handlers);
913     SET_ITEM_INT(use_hash_seed);
914     SET_ITEM_UINT(hash_seed);
915     SET_ITEM_INT(faulthandler);
916     SET_ITEM_INT(tracemalloc);
917     SET_ITEM_INT(import_time);
918     SET_ITEM_INT(show_ref_count);
919     SET_ITEM_INT(dump_refs);
920     SET_ITEM_INT(malloc_stats);
921     SET_ITEM_WSTR(filesystem_encoding);
922     SET_ITEM_WSTR(filesystem_errors);
923     SET_ITEM_WSTR(pycache_prefix);
924     SET_ITEM_WSTR(program_name);
925     SET_ITEM_INT(parse_argv);
926     SET_ITEM_WSTRLIST(argv);
927     SET_ITEM_WSTRLIST(xoptions);
928     SET_ITEM_WSTRLIST(warnoptions);
929     SET_ITEM_WSTR(pythonpath_env);
930     SET_ITEM_WSTR(home);
931     SET_ITEM_WSTRLIST(module_search_paths);
932     SET_ITEM_WSTR(executable);
933     SET_ITEM_WSTR(base_executable);
934     SET_ITEM_WSTR(prefix);
935     SET_ITEM_WSTR(base_prefix);
936     SET_ITEM_WSTR(exec_prefix);
937     SET_ITEM_WSTR(base_exec_prefix);
938     SET_ITEM_WSTR(platlibdir);
939     SET_ITEM_INT(site_import);
940     SET_ITEM_INT(bytes_warning);
941     SET_ITEM_INT(inspect);
942     SET_ITEM_INT(interactive);
943     SET_ITEM_INT(optimization_level);
944     SET_ITEM_INT(parser_debug);
945     SET_ITEM_INT(write_bytecode);
946     SET_ITEM_INT(verbose);
947     SET_ITEM_INT(quiet);
948     SET_ITEM_INT(user_site_directory);
949     SET_ITEM_INT(configure_c_stdio);
950     SET_ITEM_INT(buffered_stdio);
951     SET_ITEM_WSTR(stdio_encoding);
952     SET_ITEM_WSTR(stdio_errors);
953 #ifdef MS_WINDOWS
954     SET_ITEM_INT(legacy_windows_stdio);
955 #endif
956     SET_ITEM_INT(skip_source_first_line);
957     SET_ITEM_WSTR(run_command);
958     SET_ITEM_WSTR(run_module);
959     SET_ITEM_WSTR(run_filename);
960     SET_ITEM_INT(_install_importlib);
961     SET_ITEM_WSTR(check_hash_pycs_mode);
962     SET_ITEM_INT(pathconfig_warnings);
963     SET_ITEM_INT(_init_main);
964     SET_ITEM_INT(_isolated_interpreter);
965     SET_ITEM_WSTRLIST(_orig_argv);
966 
967     return dict;
968 
969 fail:
970     Py_DECREF(dict);
971     return NULL;
972 
973 #undef FROM_WSTRING
974 #undef SET_ITEM
975 #undef SET_ITEM_INT
976 #undef SET_ITEM_UINT
977 #undef SET_ITEM_WSTR
978 #undef SET_ITEM_WSTRLIST
979 }
980 
981 
982 static const char*
config_get_env(const PyConfig * config,const char * name)983 config_get_env(const PyConfig *config, const char *name)
984 {
985     return _Py_GetEnv(config->use_environment, name);
986 }
987 
988 
989 /* Get a copy of the environment variable as wchar_t*.
990    Return 0 on success, but *dest can be NULL.
991    Return -1 on memory allocation failure. Return -2 on decoding error. */
992 static PyStatus
config_get_env_dup(PyConfig * config,wchar_t ** dest,wchar_t * wname,char * name,const char * decode_err_msg)993 config_get_env_dup(PyConfig *config,
994                    wchar_t **dest,
995                    wchar_t *wname, char *name,
996                    const char *decode_err_msg)
997 {
998     assert(*dest == NULL);
999     assert(config->use_environment >= 0);
1000 
1001     if (!config->use_environment) {
1002         *dest = NULL;
1003         return _PyStatus_OK();
1004     }
1005 
1006 #ifdef MS_WINDOWS
1007     const wchar_t *var = _wgetenv(wname);
1008     if (!var || var[0] == '\0') {
1009         *dest = NULL;
1010         return _PyStatus_OK();
1011     }
1012 
1013     return PyConfig_SetString(config, dest, var);
1014 #else
1015     const char *var = getenv(name);
1016     if (!var || var[0] == '\0') {
1017         *dest = NULL;
1018         return _PyStatus_OK();
1019     }
1020 
1021     return config_set_bytes_string(config, dest, var, decode_err_msg);
1022 #endif
1023 }
1024 
1025 
1026 #define CONFIG_GET_ENV_DUP(CONFIG, DEST, WNAME, NAME) \
1027     config_get_env_dup(CONFIG, DEST, WNAME, NAME, "cannot decode " NAME)
1028 
1029 
1030 static void
config_get_global_vars(PyConfig * config)1031 config_get_global_vars(PyConfig *config)
1032 {
1033     if (config->_config_init != _PyConfig_INIT_COMPAT) {
1034         /* Python and Isolated configuration ignore global variables */
1035         return;
1036     }
1037 
1038 #define COPY_FLAG(ATTR, VALUE) \
1039         if (config->ATTR == -1) { \
1040             config->ATTR = VALUE; \
1041         }
1042 #define COPY_NOT_FLAG(ATTR, VALUE) \
1043         if (config->ATTR == -1) { \
1044             config->ATTR = !(VALUE); \
1045         }
1046 
1047     COPY_FLAG(isolated, Py_IsolatedFlag);
1048     COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
1049     COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
1050     COPY_FLAG(inspect, Py_InspectFlag);
1051     COPY_FLAG(interactive, Py_InteractiveFlag);
1052     COPY_FLAG(optimization_level, Py_OptimizeFlag);
1053     COPY_FLAG(parser_debug, Py_DebugFlag);
1054     COPY_FLAG(verbose, Py_VerboseFlag);
1055     COPY_FLAG(quiet, Py_QuietFlag);
1056 #ifdef MS_WINDOWS
1057     COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
1058 #endif
1059     COPY_NOT_FLAG(pathconfig_warnings, Py_FrozenFlag);
1060 
1061     COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag);
1062     COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
1063     COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag);
1064     COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory);
1065 
1066 #undef COPY_FLAG
1067 #undef COPY_NOT_FLAG
1068 }
1069 
1070 
1071 /* Set Py_xxx global configuration variables from 'config' configuration. */
1072 static void
config_set_global_vars(const PyConfig * config)1073 config_set_global_vars(const PyConfig *config)
1074 {
1075 #define COPY_FLAG(ATTR, VAR) \
1076         if (config->ATTR != -1) { \
1077             VAR = config->ATTR; \
1078         }
1079 #define COPY_NOT_FLAG(ATTR, VAR) \
1080         if (config->ATTR != -1) { \
1081             VAR = !config->ATTR; \
1082         }
1083 
1084     COPY_FLAG(isolated, Py_IsolatedFlag);
1085     COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
1086     COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
1087     COPY_FLAG(inspect, Py_InspectFlag);
1088     COPY_FLAG(interactive, Py_InteractiveFlag);
1089     COPY_FLAG(optimization_level, Py_OptimizeFlag);
1090     COPY_FLAG(parser_debug, Py_DebugFlag);
1091     COPY_FLAG(verbose, Py_VerboseFlag);
1092     COPY_FLAG(quiet, Py_QuietFlag);
1093 #ifdef MS_WINDOWS
1094     COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
1095 #endif
1096     COPY_NOT_FLAG(pathconfig_warnings, Py_FrozenFlag);
1097 
1098     COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag);
1099     COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
1100     COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag);
1101     COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory);
1102 
1103     /* Random or non-zero hash seed */
1104     Py_HashRandomizationFlag = (config->use_hash_seed == 0 ||
1105                                 config->hash_seed != 0);
1106 
1107 #undef COPY_FLAG
1108 #undef COPY_NOT_FLAG
1109 }
1110 
1111 
1112 /* Get the program name: use PYTHONEXECUTABLE and __PYVENV_LAUNCHER__
1113    environment variables on macOS if available. */
1114 static PyStatus
config_init_program_name(PyConfig * config)1115 config_init_program_name(PyConfig *config)
1116 {
1117     PyStatus status;
1118 
1119     /* If Py_SetProgramName() was called, use its value */
1120     const wchar_t *program_name = _Py_path_config.program_name;
1121     if (program_name != NULL) {
1122         config->program_name = _PyMem_RawWcsdup(program_name);
1123         if (config->program_name == NULL) {
1124             return _PyStatus_NO_MEMORY();
1125         }
1126         return _PyStatus_OK();
1127     }
1128 
1129 #ifdef __APPLE__
1130     /* On MacOS X, when the Python interpreter is embedded in an
1131        application bundle, it gets executed by a bootstrapping script
1132        that does os.execve() with an argv[0] that's different from the
1133        actual Python executable. This is needed to keep the Finder happy,
1134        or rather, to work around Apple's overly strict requirements of
1135        the process name. However, we still need a usable sys.executable,
1136        so the actual executable path is passed in an environment variable.
1137        See Lib/plat-mac/bundlebuilder.py for details about the bootstrap
1138        script. */
1139     const char *p = config_get_env(config, "PYTHONEXECUTABLE");
1140     if (p != NULL) {
1141         status = CONFIG_SET_BYTES_STR(config, &config->program_name, p,
1142                                       "PYTHONEXECUTABLE environment variable");
1143         if (_PyStatus_EXCEPTION(status)) {
1144             return status;
1145         }
1146         return _PyStatus_OK();
1147     }
1148 #ifdef WITH_NEXT_FRAMEWORK
1149     else {
1150         const char* pyvenv_launcher = getenv("__PYVENV_LAUNCHER__");
1151         if (pyvenv_launcher && *pyvenv_launcher) {
1152             /* Used by Mac/Tools/pythonw.c to forward
1153              * the argv0 of the stub executable
1154              */
1155             status = CONFIG_SET_BYTES_STR(config,
1156                                           &config->program_name,
1157                                           pyvenv_launcher,
1158                                           "__PYVENV_LAUNCHER__ environment variable");
1159             if (_PyStatus_EXCEPTION(status)) {
1160                 return status;
1161             }
1162 
1163             /*
1164              * This environment variable is used to communicate between
1165              * the stub launcher and the real interpreter and isn't needed
1166              * beyond this point.
1167              *
1168              * Clean up to avoid problems when launching other programs
1169              * later on.
1170              */
1171             (void)unsetenv("__PYVENV_LAUNCHER__");
1172 
1173             return _PyStatus_OK();
1174         }
1175     }
1176 #endif   /* WITH_NEXT_FRAMEWORK */
1177 #endif   /* __APPLE__ */
1178 
1179     /* Use argv[0] if available and non-empty */
1180     const PyWideStringList *argv = &config->argv;
1181     if (argv->length >= 1 && argv->items[0][0] != L'\0') {
1182         config->program_name = _PyMem_RawWcsdup(argv->items[0]);
1183         if (config->program_name == NULL) {
1184             return _PyStatus_NO_MEMORY();
1185         }
1186         return _PyStatus_OK();
1187     }
1188 
1189     /* Last fall back: hardcoded name */
1190 #ifdef MS_WINDOWS
1191     const wchar_t *default_program_name = L"python";
1192 #else
1193     const wchar_t *default_program_name = L"python3";
1194 #endif
1195     status = PyConfig_SetString(config, &config->program_name,
1196                                 default_program_name);
1197     if (_PyStatus_EXCEPTION(status)) {
1198         return status;
1199     }
1200     return _PyStatus_OK();
1201 }
1202 
1203 static PyStatus
config_init_executable(PyConfig * config)1204 config_init_executable(PyConfig *config)
1205 {
1206     assert(config->executable == NULL);
1207 
1208     /* If Py_SetProgramFullPath() was called, use its value */
1209     const wchar_t *program_full_path = _Py_path_config.program_full_path;
1210     if (program_full_path != NULL) {
1211         PyStatus status = PyConfig_SetString(config,
1212                                              &config->executable,
1213                                              program_full_path);
1214         if (_PyStatus_EXCEPTION(status)) {
1215             return status;
1216         }
1217         return _PyStatus_OK();
1218     }
1219     return _PyStatus_OK();
1220 }
1221 
1222 
1223 static const wchar_t*
config_get_xoption(const PyConfig * config,wchar_t * name)1224 config_get_xoption(const PyConfig *config, wchar_t *name)
1225 {
1226     return _Py_get_xoption(&config->xoptions, name);
1227 }
1228 
1229 
1230 static PyStatus
config_init_home(PyConfig * config)1231 config_init_home(PyConfig *config)
1232 {
1233     assert(config->home == NULL);
1234 
1235     /* If Py_SetPythonHome() was called, use its value */
1236     wchar_t *home = _Py_path_config.home;
1237     if (home) {
1238         PyStatus status = PyConfig_SetString(config, &config->home, home);
1239         if (_PyStatus_EXCEPTION(status)) {
1240             return status;
1241         }
1242         return _PyStatus_OK();
1243     }
1244 
1245     return CONFIG_GET_ENV_DUP(config, &config->home,
1246                               L"PYTHONHOME", "PYTHONHOME");
1247 }
1248 
1249 
1250 static PyStatus
config_init_hash_seed(PyConfig * config)1251 config_init_hash_seed(PyConfig *config)
1252 {
1253     const char *seed_text = config_get_env(config, "PYTHONHASHSEED");
1254 
1255     Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc));
1256     /* Convert a text seed to a numeric one */
1257     if (seed_text && strcmp(seed_text, "random") != 0) {
1258         const char *endptr = seed_text;
1259         unsigned long seed;
1260         errno = 0;
1261         seed = strtoul(seed_text, (char **)&endptr, 10);
1262         if (*endptr != '\0'
1263             || seed > 4294967295UL
1264             || (errno == ERANGE && seed == ULONG_MAX))
1265         {
1266             return _PyStatus_ERR("PYTHONHASHSEED must be \"random\" "
1267                                 "or an integer in range [0; 4294967295]");
1268         }
1269         /* Use a specific hash */
1270         config->use_hash_seed = 1;
1271         config->hash_seed = seed;
1272     }
1273     else {
1274         /* Use a random hash */
1275         config->use_hash_seed = 0;
1276         config->hash_seed = 0;
1277     }
1278     return _PyStatus_OK();
1279 }
1280 
1281 
1282 static int
config_wstr_to_int(const wchar_t * wstr,int * result)1283 config_wstr_to_int(const wchar_t *wstr, int *result)
1284 {
1285     const wchar_t *endptr = wstr;
1286     errno = 0;
1287     long value = wcstol(wstr, (wchar_t **)&endptr, 10);
1288     if (*endptr != '\0' || errno == ERANGE) {
1289         return -1;
1290     }
1291     if (value < INT_MIN || value > INT_MAX) {
1292         return -1;
1293     }
1294 
1295     *result = (int)value;
1296     return 0;
1297 }
1298 
1299 
1300 static PyStatus
config_read_env_vars(PyConfig * config)1301 config_read_env_vars(PyConfig *config)
1302 {
1303     PyStatus status;
1304     int use_env = config->use_environment;
1305 
1306     /* Get environment variables */
1307     _Py_get_env_flag(use_env, &config->parser_debug, "PYTHONDEBUG");
1308     _Py_get_env_flag(use_env, &config->verbose, "PYTHONVERBOSE");
1309     _Py_get_env_flag(use_env, &config->optimization_level, "PYTHONOPTIMIZE");
1310     _Py_get_env_flag(use_env, &config->inspect, "PYTHONINSPECT");
1311 
1312     int dont_write_bytecode = 0;
1313     _Py_get_env_flag(use_env, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE");
1314     if (dont_write_bytecode) {
1315         config->write_bytecode = 0;
1316     }
1317 
1318     int no_user_site_directory = 0;
1319     _Py_get_env_flag(use_env, &no_user_site_directory, "PYTHONNOUSERSITE");
1320     if (no_user_site_directory) {
1321         config->user_site_directory = 0;
1322     }
1323 
1324     int unbuffered_stdio = 0;
1325     _Py_get_env_flag(use_env, &unbuffered_stdio, "PYTHONUNBUFFERED");
1326     if (unbuffered_stdio) {
1327         config->buffered_stdio = 0;
1328     }
1329 
1330 #ifdef MS_WINDOWS
1331     _Py_get_env_flag(use_env, &config->legacy_windows_stdio,
1332                  "PYTHONLEGACYWINDOWSSTDIO");
1333 #endif
1334 
1335     if (config_get_env(config, "PYTHONDUMPREFS")) {
1336         config->dump_refs = 1;
1337     }
1338     if (config_get_env(config, "PYTHONMALLOCSTATS")) {
1339         config->malloc_stats = 1;
1340     }
1341 
1342     if (config->pythonpath_env == NULL) {
1343         status = CONFIG_GET_ENV_DUP(config, &config->pythonpath_env,
1344                                     L"PYTHONPATH", "PYTHONPATH");
1345         if (_PyStatus_EXCEPTION(status)) {
1346             return status;
1347         }
1348     }
1349 
1350     if(config->platlibdir == NULL) {
1351         status = CONFIG_GET_ENV_DUP(config, &config->platlibdir,
1352                                     L"PYTHONPLATLIBDIR", "PYTHONPLATLIBDIR");
1353         if (_PyStatus_EXCEPTION(status)) {
1354             return status;
1355         }
1356     }
1357 
1358     if (config->use_hash_seed < 0) {
1359         status = config_init_hash_seed(config);
1360         if (_PyStatus_EXCEPTION(status)) {
1361             return status;
1362         }
1363     }
1364 
1365     return _PyStatus_OK();
1366 }
1367 
1368 
1369 static PyStatus
config_init_tracemalloc(PyConfig * config)1370 config_init_tracemalloc(PyConfig *config)
1371 {
1372     int nframe;
1373     int valid;
1374 
1375     const char *env = config_get_env(config, "PYTHONTRACEMALLOC");
1376     if (env) {
1377         if (!_Py_str_to_int(env, &nframe)) {
1378             valid = (nframe >= 0);
1379         }
1380         else {
1381             valid = 0;
1382         }
1383         if (!valid) {
1384             return _PyStatus_ERR("PYTHONTRACEMALLOC: invalid number of frames");
1385         }
1386         config->tracemalloc = nframe;
1387     }
1388 
1389     const wchar_t *xoption = config_get_xoption(config, L"tracemalloc");
1390     if (xoption) {
1391         const wchar_t *sep = wcschr(xoption, L'=');
1392         if (sep) {
1393             if (!config_wstr_to_int(sep + 1, &nframe)) {
1394                 valid = (nframe >= 0);
1395             }
1396             else {
1397                 valid = 0;
1398             }
1399             if (!valid) {
1400                 return _PyStatus_ERR("-X tracemalloc=NFRAME: "
1401                                      "invalid number of frames");
1402             }
1403         }
1404         else {
1405             /* -X tracemalloc behaves as -X tracemalloc=1 */
1406             nframe = 1;
1407         }
1408         config->tracemalloc = nframe;
1409     }
1410     return _PyStatus_OK();
1411 }
1412 
1413 
1414 static PyStatus
config_init_pycache_prefix(PyConfig * config)1415 config_init_pycache_prefix(PyConfig *config)
1416 {
1417     assert(config->pycache_prefix == NULL);
1418 
1419     const wchar_t *xoption = config_get_xoption(config, L"pycache_prefix");
1420     if (xoption) {
1421         const wchar_t *sep = wcschr(xoption, L'=');
1422         if (sep && wcslen(sep) > 1) {
1423             config->pycache_prefix = _PyMem_RawWcsdup(sep + 1);
1424             if (config->pycache_prefix == NULL) {
1425                 return _PyStatus_NO_MEMORY();
1426             }
1427         }
1428         else {
1429             // PYTHONPYCACHEPREFIX env var ignored
1430             // if "-X pycache_prefix=" option is used
1431             config->pycache_prefix = NULL;
1432         }
1433         return _PyStatus_OK();
1434     }
1435 
1436     return CONFIG_GET_ENV_DUP(config, &config->pycache_prefix,
1437                               L"PYTHONPYCACHEPREFIX",
1438                               "PYTHONPYCACHEPREFIX");
1439 }
1440 
1441 
1442 static PyStatus
config_read_complex_options(PyConfig * config)1443 config_read_complex_options(PyConfig *config)
1444 {
1445     /* More complex options configured by env var and -X option */
1446     if (config->faulthandler < 0) {
1447         if (config_get_env(config, "PYTHONFAULTHANDLER")
1448            || config_get_xoption(config, L"faulthandler")) {
1449             config->faulthandler = 1;
1450         }
1451     }
1452     if (config_get_env(config, "PYTHONPROFILEIMPORTTIME")
1453        || config_get_xoption(config, L"importtime")) {
1454         config->import_time = 1;
1455     }
1456 
1457     if (config_get_env(config, "PYTHONOLDPARSER")
1458        || config_get_xoption(config, L"oldparser")) {
1459         config->_use_peg_parser = 0;
1460     }
1461 
1462     PyStatus status;
1463     if (config->tracemalloc < 0) {
1464         status = config_init_tracemalloc(config);
1465         if (_PyStatus_EXCEPTION(status)) {
1466             return status;
1467         }
1468     }
1469 
1470     if (config->pycache_prefix == NULL) {
1471         status = config_init_pycache_prefix(config);
1472         if (_PyStatus_EXCEPTION(status)) {
1473             return status;
1474         }
1475     }
1476     return _PyStatus_OK();
1477 }
1478 
1479 
1480 static const wchar_t *
config_get_stdio_errors(void)1481 config_get_stdio_errors(void)
1482 {
1483 #ifndef MS_WINDOWS
1484     const char *loc = setlocale(LC_CTYPE, NULL);
1485     if (loc != NULL) {
1486         /* surrogateescape is the default in the legacy C and POSIX locales */
1487         if (strcmp(loc, "C") == 0 || strcmp(loc, "POSIX") == 0) {
1488             return L"surrogateescape";
1489         }
1490 
1491 #ifdef PY_COERCE_C_LOCALE
1492         /* surrogateescape is the default in locale coercion target locales */
1493         if (_Py_IsLocaleCoercionTarget(loc)) {
1494             return L"surrogateescape";
1495         }
1496 #endif
1497     }
1498 
1499     return L"strict";
1500 #else
1501     /* On Windows, always use surrogateescape by default */
1502     return L"surrogateescape";
1503 #endif
1504 }
1505 
1506 
1507 static PyStatus
config_get_locale_encoding(PyConfig * config,wchar_t ** locale_encoding)1508 config_get_locale_encoding(PyConfig *config, wchar_t **locale_encoding)
1509 {
1510 #ifdef MS_WINDOWS
1511     char encoding[20];
1512     PyOS_snprintf(encoding, sizeof(encoding), "cp%u", GetACP());
1513     return PyConfig_SetBytesString(config, locale_encoding, encoding);
1514 #elif defined(_Py_FORCE_UTF8_LOCALE)
1515     return PyConfig_SetString(config, locale_encoding, L"utf-8");
1516 #else
1517     const char *encoding = nl_langinfo(CODESET);
1518     if (!encoding || encoding[0] == '\0') {
1519         return _PyStatus_ERR("failed to get the locale encoding: "
1520                              "nl_langinfo(CODESET) failed");
1521     }
1522     /* nl_langinfo(CODESET) is decoded by Py_DecodeLocale() */
1523     return CONFIG_SET_BYTES_STR(config,
1524                                 locale_encoding, encoding,
1525                                 "nl_langinfo(CODESET)");
1526 #endif
1527 }
1528 
1529 
1530 static PyStatus
config_init_stdio_encoding(PyConfig * config,const PyPreConfig * preconfig)1531 config_init_stdio_encoding(PyConfig *config,
1532                            const PyPreConfig *preconfig)
1533 {
1534     PyStatus status;
1535 
1536     /* If Py_SetStandardStreamEncoding() have been called, use these
1537         parameters. */
1538     if (config->stdio_encoding == NULL && _Py_StandardStreamEncoding != NULL) {
1539         status = CONFIG_SET_BYTES_STR(config, &config->stdio_encoding,
1540                                       _Py_StandardStreamEncoding,
1541                                       "_Py_StandardStreamEncoding");
1542         if (_PyStatus_EXCEPTION(status)) {
1543             return status;
1544         }
1545     }
1546 
1547     if (config->stdio_errors == NULL && _Py_StandardStreamErrors != NULL) {
1548         status = CONFIG_SET_BYTES_STR(config, &config->stdio_errors,
1549                                       _Py_StandardStreamErrors,
1550                                       "_Py_StandardStreamErrors");
1551         if (_PyStatus_EXCEPTION(status)) {
1552             return status;
1553         }
1554     }
1555 
1556     if (config->stdio_encoding != NULL && config->stdio_errors != NULL) {
1557         return _PyStatus_OK();
1558     }
1559 
1560     /* PYTHONIOENCODING environment variable */
1561     const char *opt = config_get_env(config, "PYTHONIOENCODING");
1562     if (opt) {
1563         char *pythonioencoding = _PyMem_RawStrdup(opt);
1564         if (pythonioencoding == NULL) {
1565             return _PyStatus_NO_MEMORY();
1566         }
1567 
1568         char *errors = strchr(pythonioencoding, ':');
1569         if (errors) {
1570             *errors = '\0';
1571             errors++;
1572             if (!errors[0]) {
1573                 errors = NULL;
1574             }
1575         }
1576 
1577         /* Does PYTHONIOENCODING contain an encoding? */
1578         if (pythonioencoding[0]) {
1579             if (config->stdio_encoding == NULL) {
1580                 status = CONFIG_SET_BYTES_STR(config, &config->stdio_encoding,
1581                                               pythonioencoding,
1582                                               "PYTHONIOENCODING environment variable");
1583                 if (_PyStatus_EXCEPTION(status)) {
1584                     PyMem_RawFree(pythonioencoding);
1585                     return status;
1586                 }
1587             }
1588 
1589             /* If the encoding is set but not the error handler,
1590                use "strict" error handler by default.
1591                PYTHONIOENCODING=latin1 behaves as
1592                PYTHONIOENCODING=latin1:strict. */
1593             if (!errors) {
1594                 errors = "strict";
1595             }
1596         }
1597 
1598         if (config->stdio_errors == NULL && errors != NULL) {
1599             status = CONFIG_SET_BYTES_STR(config, &config->stdio_errors,
1600                                           errors,
1601                                           "PYTHONIOENCODING environment variable");
1602             if (_PyStatus_EXCEPTION(status)) {
1603                 PyMem_RawFree(pythonioencoding);
1604                 return status;
1605             }
1606         }
1607 
1608         PyMem_RawFree(pythonioencoding);
1609     }
1610 
1611     /* UTF-8 Mode uses UTF-8/surrogateescape */
1612     if (preconfig->utf8_mode) {
1613         if (config->stdio_encoding == NULL) {
1614             status = PyConfig_SetString(config, &config->stdio_encoding,
1615                                         L"utf-8");
1616             if (_PyStatus_EXCEPTION(status)) {
1617                 return status;
1618             }
1619         }
1620         if (config->stdio_errors == NULL) {
1621             status = PyConfig_SetString(config, &config->stdio_errors,
1622                                         L"surrogateescape");
1623             if (_PyStatus_EXCEPTION(status)) {
1624                 return status;
1625             }
1626         }
1627     }
1628 
1629     /* Choose the default error handler based on the current locale. */
1630     if (config->stdio_encoding == NULL) {
1631         status = config_get_locale_encoding(config, &config->stdio_encoding);
1632         if (_PyStatus_EXCEPTION(status)) {
1633             return status;
1634         }
1635     }
1636     if (config->stdio_errors == NULL) {
1637         const wchar_t *errors = config_get_stdio_errors();
1638         assert(errors != NULL);
1639 
1640         status = PyConfig_SetString(config, &config->stdio_errors, errors);
1641         if (_PyStatus_EXCEPTION(status)) {
1642             return status;
1643         }
1644     }
1645 
1646     return _PyStatus_OK();
1647 }
1648 
1649 
1650 static PyStatus
config_init_fs_encoding(PyConfig * config,const PyPreConfig * preconfig)1651 config_init_fs_encoding(PyConfig *config, const PyPreConfig *preconfig)
1652 {
1653     PyStatus status;
1654 
1655     if (config->filesystem_encoding == NULL) {
1656 #ifdef _Py_FORCE_UTF8_FS_ENCODING
1657         status = PyConfig_SetString(config, &config->filesystem_encoding, L"utf-8");
1658 #else
1659 
1660 #ifdef MS_WINDOWS
1661         if (preconfig->legacy_windows_fs_encoding) {
1662             /* Legacy Windows filesystem encoding: mbcs/replace */
1663             status = PyConfig_SetString(config, &config->filesystem_encoding,
1664                                         L"mbcs");
1665         }
1666         else
1667 #endif
1668         if (preconfig->utf8_mode) {
1669             status = PyConfig_SetString(config, &config->filesystem_encoding,
1670                                         L"utf-8");
1671         }
1672 #ifndef MS_WINDOWS
1673         else if (_Py_GetForceASCII()) {
1674             status = PyConfig_SetString(config, &config->filesystem_encoding,
1675                                         L"ascii");
1676         }
1677 #endif
1678         else {
1679 #ifdef MS_WINDOWS
1680             /* Windows defaults to utf-8/surrogatepass (PEP 529). */
1681             status = PyConfig_SetString(config, &config->filesystem_encoding,
1682                                         L"utf-8");
1683 #else
1684             status = config_get_locale_encoding(config,
1685                                                 &config->filesystem_encoding);
1686 #endif
1687         }
1688 #endif   /* !_Py_FORCE_UTF8_FS_ENCODING */
1689 
1690         if (_PyStatus_EXCEPTION(status)) {
1691             return status;
1692         }
1693     }
1694 
1695     if (config->filesystem_errors == NULL) {
1696         const wchar_t *errors;
1697 #ifdef MS_WINDOWS
1698         if (preconfig->legacy_windows_fs_encoding) {
1699             errors = L"replace";
1700         }
1701         else {
1702             errors = L"surrogatepass";
1703         }
1704 #else
1705         errors = L"surrogateescape";
1706 #endif
1707         status = PyConfig_SetString(config, &config->filesystem_errors, errors);
1708         if (_PyStatus_EXCEPTION(status)) {
1709             return status;
1710         }
1711     }
1712     return _PyStatus_OK();
1713 }
1714 
1715 
1716 static PyStatus
config_read(PyConfig * config)1717 config_read(PyConfig *config)
1718 {
1719     PyStatus status;
1720     const PyPreConfig *preconfig = &_PyRuntime.preconfig;
1721 
1722     if (config->use_environment) {
1723         status = config_read_env_vars(config);
1724         if (_PyStatus_EXCEPTION(status)) {
1725             return status;
1726         }
1727     }
1728 
1729     /* -X options */
1730     if (config_get_xoption(config, L"showrefcount")) {
1731         config->show_ref_count = 1;
1732     }
1733 
1734     status = config_read_complex_options(config);
1735     if (_PyStatus_EXCEPTION(status)) {
1736         return status;
1737     }
1738 
1739     if (config->home == NULL) {
1740         status = config_init_home(config);
1741         if (_PyStatus_EXCEPTION(status)) {
1742             return status;
1743         }
1744     }
1745 
1746     if (config->executable == NULL) {
1747         status = config_init_executable(config);
1748         if (_PyStatus_EXCEPTION(status)) {
1749             return status;
1750         }
1751     }
1752 
1753     if(config->platlibdir == NULL) {
1754         status = CONFIG_SET_BYTES_STR(config, &config->platlibdir, PLATLIBDIR,
1755                                       "PLATLIBDIR macro");
1756         if (_PyStatus_EXCEPTION(status)) {
1757             return status;
1758         }
1759     }
1760 
1761     if (config->_install_importlib) {
1762         status = _PyConfig_InitPathConfig(config);
1763         if (_PyStatus_EXCEPTION(status)) {
1764             return status;
1765         }
1766     }
1767 
1768     /* default values */
1769     if (config->dev_mode) {
1770         if (config->faulthandler < 0) {
1771             config->faulthandler = 1;
1772         }
1773     }
1774     if (config->faulthandler < 0) {
1775         config->faulthandler = 0;
1776     }
1777     if (config->tracemalloc < 0) {
1778         config->tracemalloc = 0;
1779     }
1780     if (config->use_hash_seed < 0) {
1781         config->use_hash_seed = 0;
1782         config->hash_seed = 0;
1783     }
1784 
1785     if (config->filesystem_encoding == NULL || config->filesystem_errors == NULL) {
1786         status = config_init_fs_encoding(config, preconfig);
1787         if (_PyStatus_EXCEPTION(status)) {
1788             return status;
1789         }
1790     }
1791 
1792     status = config_init_stdio_encoding(config, preconfig);
1793     if (_PyStatus_EXCEPTION(status)) {
1794         return status;
1795     }
1796 
1797     if (config->argv.length < 1) {
1798         /* Ensure at least one (empty) argument is seen */
1799         status = PyWideStringList_Append(&config->argv, L"");
1800         if (_PyStatus_EXCEPTION(status)) {
1801             return status;
1802         }
1803     }
1804 
1805     if (config->check_hash_pycs_mode == NULL) {
1806         status = PyConfig_SetString(config, &config->check_hash_pycs_mode,
1807                                     L"default");
1808         if (_PyStatus_EXCEPTION(status)) {
1809             return status;
1810         }
1811     }
1812 
1813     if (config->configure_c_stdio < 0) {
1814         config->configure_c_stdio = 1;
1815     }
1816 
1817     return _PyStatus_OK();
1818 }
1819 
1820 
1821 static void
config_init_stdio(const PyConfig * config)1822 config_init_stdio(const PyConfig *config)
1823 {
1824 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
1825     /* don't translate newlines (\r\n <=> \n) */
1826     _setmode(fileno(stdin), O_BINARY);
1827     _setmode(fileno(stdout), O_BINARY);
1828     _setmode(fileno(stderr), O_BINARY);
1829 #endif
1830 
1831     if (!config->buffered_stdio) {
1832 #ifdef HAVE_SETVBUF
1833         setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
1834         setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
1835         setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
1836 #else /* !HAVE_SETVBUF */
1837         setbuf(stdin,  (char *)NULL);
1838         setbuf(stdout, (char *)NULL);
1839         setbuf(stderr, (char *)NULL);
1840 #endif /* !HAVE_SETVBUF */
1841     }
1842     else if (config->interactive) {
1843 #ifdef MS_WINDOWS
1844         /* Doesn't have to have line-buffered -- use unbuffered */
1845         /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
1846         setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
1847 #else /* !MS_WINDOWS */
1848 #ifdef HAVE_SETVBUF
1849         setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
1850         setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
1851 #endif /* HAVE_SETVBUF */
1852 #endif /* !MS_WINDOWS */
1853         /* Leave stderr alone - it should be unbuffered anyway. */
1854     }
1855 }
1856 
1857 
1858 /* Write the configuration:
1859 
1860    - set Py_xxx global configuration variables
1861    - initialize C standard streams (stdin, stdout, stderr) */
1862 PyStatus
_PyConfig_Write(const PyConfig * config,_PyRuntimeState * runtime)1863 _PyConfig_Write(const PyConfig *config, _PyRuntimeState *runtime)
1864 {
1865     config_set_global_vars(config);
1866 
1867     if (config->configure_c_stdio) {
1868         config_init_stdio(config);
1869     }
1870 
1871     /* Write the new pre-configuration into _PyRuntime */
1872     PyPreConfig *preconfig = &runtime->preconfig;
1873     preconfig->isolated = config->isolated;
1874     preconfig->use_environment = config->use_environment;
1875     preconfig->dev_mode = config->dev_mode;
1876 
1877     if (_Py_SetArgcArgv(config->_orig_argv.length,
1878                         config->_orig_argv.items) < 0)
1879     {
1880         return _PyStatus_NO_MEMORY();
1881     }
1882     return _PyStatus_OK();
1883 }
1884 
1885 
1886 /* --- PyConfig command line parser -------------------------- */
1887 
1888 static void
config_usage(int error,const wchar_t * program)1889 config_usage(int error, const wchar_t* program)
1890 {
1891     FILE *f = error ? stderr : stdout;
1892 
1893     fprintf(f, usage_line, program);
1894     if (error)
1895         fprintf(f, "Try `python -h' for more information.\n");
1896     else {
1897         fputs(usage_1, f);
1898         fputs(usage_2, f);
1899         fputs(usage_3, f);
1900         fprintf(f, usage_4, (wint_t)DELIM);
1901         fprintf(f, usage_5, (wint_t)DELIM, PYTHONHOMEHELP);
1902         fputs(usage_6, f);
1903     }
1904 }
1905 
1906 
1907 /* Parse the command line arguments */
1908 static PyStatus
config_parse_cmdline(PyConfig * config,PyWideStringList * warnoptions,Py_ssize_t * opt_index)1909 config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
1910                      Py_ssize_t *opt_index)
1911 {
1912     PyStatus status;
1913     const PyWideStringList *argv = &config->argv;
1914     int print_version = 0;
1915     const wchar_t* program = config->program_name;
1916 
1917     _PyOS_ResetGetOpt();
1918     do {
1919         int longindex = -1;
1920         int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
1921         if (c == EOF) {
1922             break;
1923         }
1924 
1925         if (c == 'c') {
1926             if (config->run_command == NULL) {
1927                 /* -c is the last option; following arguments
1928                    that look like options are left for the
1929                    command to interpret. */
1930                 size_t len = wcslen(_PyOS_optarg) + 1 + 1;
1931                 wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
1932                 if (command == NULL) {
1933                     return _PyStatus_NO_MEMORY();
1934                 }
1935                 memcpy(command, _PyOS_optarg, (len - 2) * sizeof(wchar_t));
1936                 command[len - 2] = '\n';
1937                 command[len - 1] = 0;
1938                 config->run_command = command;
1939             }
1940             break;
1941         }
1942 
1943         if (c == 'm') {
1944             /* -m is the last option; following arguments
1945                that look like options are left for the
1946                module to interpret. */
1947             if (config->run_module == NULL) {
1948                 config->run_module = _PyMem_RawWcsdup(_PyOS_optarg);
1949                 if (config->run_module == NULL) {
1950                     return _PyStatus_NO_MEMORY();
1951                 }
1952             }
1953             break;
1954         }
1955 
1956         switch (c) {
1957         case 0:
1958             // Handle long option.
1959             assert(longindex == 0); // Only one long option now.
1960             if (wcscmp(_PyOS_optarg, L"always") == 0
1961                 || wcscmp(_PyOS_optarg, L"never") == 0
1962                 || wcscmp(_PyOS_optarg, L"default") == 0)
1963             {
1964                 status = PyConfig_SetString(config, &config->check_hash_pycs_mode,
1965                                             _PyOS_optarg);
1966                 if (_PyStatus_EXCEPTION(status)) {
1967                     return status;
1968                 }
1969             } else {
1970                 fprintf(stderr, "--check-hash-based-pycs must be one of "
1971                         "'default', 'always', or 'never'\n");
1972                 config_usage(1, program);
1973                 return _PyStatus_EXIT(2);
1974             }
1975             break;
1976 
1977         case 'b':
1978             config->bytes_warning++;
1979             break;
1980 
1981         case 'd':
1982             config->parser_debug++;
1983             break;
1984 
1985         case 'i':
1986             config->inspect++;
1987             config->interactive++;
1988             break;
1989 
1990         case 'E':
1991         case 'I':
1992         case 'X':
1993             /* option handled by _PyPreCmdline_Read() */
1994             break;
1995 
1996         /* case 'J': reserved for Jython */
1997 
1998         case 'O':
1999             config->optimization_level++;
2000             break;
2001 
2002         case 'B':
2003             config->write_bytecode = 0;
2004             break;
2005 
2006         case 's':
2007             config->user_site_directory = 0;
2008             break;
2009 
2010         case 'S':
2011             config->site_import = 0;
2012             break;
2013 
2014         case 't':
2015             /* ignored for backwards compatibility */
2016             break;
2017 
2018         case 'u':
2019             config->buffered_stdio = 0;
2020             break;
2021 
2022         case 'v':
2023             config->verbose++;
2024             break;
2025 
2026         case 'x':
2027             config->skip_source_first_line = 1;
2028             break;
2029 
2030         case 'h':
2031         case '?':
2032             config_usage(0, program);
2033             return _PyStatus_EXIT(0);
2034 
2035         case 'V':
2036             print_version++;
2037             break;
2038 
2039         case 'W':
2040             status = PyWideStringList_Append(warnoptions, _PyOS_optarg);
2041             if (_PyStatus_EXCEPTION(status)) {
2042                 return status;
2043             }
2044             break;
2045 
2046         case 'q':
2047             config->quiet++;
2048             break;
2049 
2050         case 'R':
2051             config->use_hash_seed = 0;
2052             break;
2053 
2054         /* This space reserved for other options */
2055 
2056         default:
2057             /* unknown argument: parsing failed */
2058             config_usage(1, program);
2059             return _PyStatus_EXIT(2);
2060         }
2061     } while (1);
2062 
2063     if (print_version) {
2064         printf("Python %s\n",
2065                 (print_version >= 2) ? Py_GetVersion() : PY_VERSION);
2066         return _PyStatus_EXIT(0);
2067     }
2068 
2069     if (config->run_command == NULL && config->run_module == NULL
2070         && _PyOS_optind < argv->length
2071         && wcscmp(argv->items[_PyOS_optind], L"-") != 0
2072         && config->run_filename == NULL)
2073     {
2074         config->run_filename = _PyMem_RawWcsdup(argv->items[_PyOS_optind]);
2075         if (config->run_filename == NULL) {
2076             return _PyStatus_NO_MEMORY();
2077         }
2078     }
2079 
2080     if (config->run_command != NULL || config->run_module != NULL) {
2081         /* Backup _PyOS_optind */
2082         _PyOS_optind--;
2083     }
2084 
2085     *opt_index = _PyOS_optind;
2086 
2087     return _PyStatus_OK();
2088 }
2089 
2090 
2091 #ifdef MS_WINDOWS
2092 #  define WCSTOK wcstok_s
2093 #else
2094 #  define WCSTOK wcstok
2095 #endif
2096 
2097 /* Get warning options from PYTHONWARNINGS environment variable. */
2098 static PyStatus
config_init_env_warnoptions(PyConfig * config,PyWideStringList * warnoptions)2099 config_init_env_warnoptions(PyConfig *config, PyWideStringList *warnoptions)
2100 {
2101     PyStatus status;
2102     /* CONFIG_GET_ENV_DUP requires dest to be initialized to NULL */
2103     wchar_t *env = NULL;
2104     status = CONFIG_GET_ENV_DUP(config, &env,
2105                              L"PYTHONWARNINGS", "PYTHONWARNINGS");
2106     if (_PyStatus_EXCEPTION(status)) {
2107         return status;
2108     }
2109 
2110     /* env var is not set or is empty */
2111     if (env == NULL) {
2112         return _PyStatus_OK();
2113     }
2114 
2115 
2116     wchar_t *warning, *context = NULL;
2117     for (warning = WCSTOK(env, L",", &context);
2118          warning != NULL;
2119          warning = WCSTOK(NULL, L",", &context))
2120     {
2121         status = PyWideStringList_Append(warnoptions, warning);
2122         if (_PyStatus_EXCEPTION(status)) {
2123             PyMem_RawFree(env);
2124             return status;
2125         }
2126     }
2127     PyMem_RawFree(env);
2128     return _PyStatus_OK();
2129 }
2130 
2131 
2132 static PyStatus
warnoptions_append(PyConfig * config,PyWideStringList * options,const wchar_t * option)2133 warnoptions_append(PyConfig *config, PyWideStringList *options,
2134                    const wchar_t *option)
2135 {
2136     /* config_init_warnoptions() add existing config warnoptions at the end:
2137        ensure that the new option is not already present in this list to
2138        prevent change the options order whne config_init_warnoptions() is
2139        called twice. */
2140     if (_PyWideStringList_Find(&config->warnoptions, option)) {
2141         /* Already present: do nothing */
2142         return _PyStatus_OK();
2143     }
2144     if (_PyWideStringList_Find(options, option)) {
2145         /* Already present: do nothing */
2146         return _PyStatus_OK();
2147     }
2148     return PyWideStringList_Append(options, option);
2149 }
2150 
2151 
2152 static PyStatus
warnoptions_extend(PyConfig * config,PyWideStringList * options,const PyWideStringList * options2)2153 warnoptions_extend(PyConfig *config, PyWideStringList *options,
2154                    const PyWideStringList *options2)
2155 {
2156     const Py_ssize_t len = options2->length;
2157     wchar_t *const *items = options2->items;
2158 
2159     for (Py_ssize_t i = 0; i < len; i++) {
2160         PyStatus status = warnoptions_append(config, options, items[i]);
2161         if (_PyStatus_EXCEPTION(status)) {
2162             return status;
2163         }
2164     }
2165     return _PyStatus_OK();
2166 }
2167 
2168 
2169 static PyStatus
config_init_warnoptions(PyConfig * config,const PyWideStringList * cmdline_warnoptions,const PyWideStringList * env_warnoptions,const PyWideStringList * sys_warnoptions)2170 config_init_warnoptions(PyConfig *config,
2171                         const PyWideStringList *cmdline_warnoptions,
2172                         const PyWideStringList *env_warnoptions,
2173                         const PyWideStringList *sys_warnoptions)
2174 {
2175     PyStatus status;
2176     PyWideStringList options = _PyWideStringList_INIT;
2177 
2178     /* Priority of warnings options, lowest to highest:
2179      *
2180      * - any implicit filters added by _warnings.c/warnings.py
2181      * - PyConfig.dev_mode: "default" filter
2182      * - PYTHONWARNINGS environment variable
2183      * - '-W' command line options
2184      * - PyConfig.bytes_warning ('-b' and '-bb' command line options):
2185      *   "default::BytesWarning" or "error::BytesWarning" filter
2186      * - early PySys_AddWarnOption() calls
2187      * - PyConfig.warnoptions
2188      *
2189      * PyConfig.warnoptions is copied to sys.warnoptions. Since the warnings
2190      * module works on the basis of "the most recently added filter will be
2191      * checked first", we add the lowest precedence entries first so that later
2192      * entries override them.
2193      */
2194 
2195     if (config->dev_mode) {
2196         status = warnoptions_append(config, &options, L"default");
2197         if (_PyStatus_EXCEPTION(status)) {
2198             goto error;
2199         }
2200     }
2201 
2202     status = warnoptions_extend(config, &options, env_warnoptions);
2203     if (_PyStatus_EXCEPTION(status)) {
2204         goto error;
2205     }
2206 
2207     status = warnoptions_extend(config, &options, cmdline_warnoptions);
2208     if (_PyStatus_EXCEPTION(status)) {
2209         goto error;
2210     }
2211 
2212     /* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c
2213      * don't even try to emit a warning, so we skip setting the filter in that
2214      * case.
2215      */
2216     if (config->bytes_warning) {
2217         const wchar_t *filter;
2218         if (config->bytes_warning> 1) {
2219             filter = L"error::BytesWarning";
2220         }
2221         else {
2222             filter = L"default::BytesWarning";
2223         }
2224         status = warnoptions_append(config, &options, filter);
2225         if (_PyStatus_EXCEPTION(status)) {
2226             goto error;
2227         }
2228     }
2229 
2230     status = warnoptions_extend(config, &options, sys_warnoptions);
2231     if (_PyStatus_EXCEPTION(status)) {
2232         goto error;
2233     }
2234 
2235     /* Always add all PyConfig.warnoptions options */
2236     status = _PyWideStringList_Extend(&options, &config->warnoptions);
2237     if (_PyStatus_EXCEPTION(status)) {
2238         goto error;
2239     }
2240 
2241     _PyWideStringList_Clear(&config->warnoptions);
2242     config->warnoptions = options;
2243     return _PyStatus_OK();
2244 
2245 error:
2246     _PyWideStringList_Clear(&options);
2247     return status;
2248 }
2249 
2250 
2251 static PyStatus
config_update_argv(PyConfig * config,Py_ssize_t opt_index)2252 config_update_argv(PyConfig *config, Py_ssize_t opt_index)
2253 {
2254     const PyWideStringList *cmdline_argv = &config->argv;
2255     PyWideStringList config_argv = _PyWideStringList_INIT;
2256 
2257     /* Copy argv to be able to modify it (to force -c/-m) */
2258     if (cmdline_argv->length <= opt_index) {
2259         /* Ensure at least one (empty) argument is seen */
2260         PyStatus status = PyWideStringList_Append(&config_argv, L"");
2261         if (_PyStatus_EXCEPTION(status)) {
2262             return status;
2263         }
2264     }
2265     else {
2266         PyWideStringList slice;
2267         slice.length = cmdline_argv->length - opt_index;
2268         slice.items = &cmdline_argv->items[opt_index];
2269         if (_PyWideStringList_Copy(&config_argv, &slice) < 0) {
2270             return _PyStatus_NO_MEMORY();
2271         }
2272     }
2273     assert(config_argv.length >= 1);
2274 
2275     wchar_t *arg0 = NULL;
2276     if (config->run_command != NULL) {
2277         /* Force sys.argv[0] = '-c' */
2278         arg0 = L"-c";
2279     }
2280     else if (config->run_module != NULL) {
2281         /* Force sys.argv[0] = '-m'*/
2282         arg0 = L"-m";
2283     }
2284 
2285     if (arg0 != NULL) {
2286         arg0 = _PyMem_RawWcsdup(arg0);
2287         if (arg0 == NULL) {
2288             _PyWideStringList_Clear(&config_argv);
2289             return _PyStatus_NO_MEMORY();
2290         }
2291 
2292         PyMem_RawFree(config_argv.items[0]);
2293         config_argv.items[0] = arg0;
2294     }
2295 
2296     _PyWideStringList_Clear(&config->argv);
2297     config->argv = config_argv;
2298     return _PyStatus_OK();
2299 }
2300 
2301 
2302 static PyStatus
core_read_precmdline(PyConfig * config,_PyPreCmdline * precmdline)2303 core_read_precmdline(PyConfig *config, _PyPreCmdline *precmdline)
2304 {
2305     PyStatus status;
2306 
2307     if (config->parse_argv) {
2308         if (_PyWideStringList_Copy(&precmdline->argv, &config->argv) < 0) {
2309             return _PyStatus_NO_MEMORY();
2310         }
2311     }
2312 
2313     PyPreConfig preconfig;
2314 
2315     status = _PyPreConfig_InitFromPreConfig(&preconfig, &_PyRuntime.preconfig);
2316     if (_PyStatus_EXCEPTION(status)) {
2317         return status;
2318     }
2319 
2320     _PyPreConfig_GetConfig(&preconfig, config);
2321 
2322     status = _PyPreCmdline_Read(precmdline, &preconfig);
2323     if (_PyStatus_EXCEPTION(status)) {
2324         return status;
2325     }
2326 
2327     status = _PyPreCmdline_SetConfig(precmdline, config);
2328     if (_PyStatus_EXCEPTION(status)) {
2329         return status;
2330     }
2331     return _PyStatus_OK();
2332 }
2333 
2334 
2335 /* Get run_filename absolute path */
2336 static PyStatus
config_run_filename_abspath(PyConfig * config)2337 config_run_filename_abspath(PyConfig *config)
2338 {
2339     if (!config->run_filename) {
2340         return _PyStatus_OK();
2341     }
2342 
2343 #ifndef MS_WINDOWS
2344     if (_Py_isabs(config->run_filename)) {
2345         /* path is already absolute */
2346         return _PyStatus_OK();
2347     }
2348 #endif
2349 
2350     wchar_t *abs_filename;
2351     if (_Py_abspath(config->run_filename, &abs_filename) < 0) {
2352         /* failed to get the absolute path of the command line filename:
2353            ignore the error, keep the relative path */
2354         return _PyStatus_OK();
2355     }
2356     if (abs_filename == NULL) {
2357         return _PyStatus_NO_MEMORY();
2358     }
2359 
2360     PyMem_RawFree(config->run_filename);
2361     config->run_filename = abs_filename;
2362     return _PyStatus_OK();
2363 }
2364 
2365 
2366 static PyStatus
config_read_cmdline(PyConfig * config)2367 config_read_cmdline(PyConfig *config)
2368 {
2369     PyStatus status;
2370     PyWideStringList cmdline_warnoptions = _PyWideStringList_INIT;
2371     PyWideStringList env_warnoptions = _PyWideStringList_INIT;
2372     PyWideStringList sys_warnoptions = _PyWideStringList_INIT;
2373 
2374     if (config->parse_argv < 0) {
2375         config->parse_argv = 1;
2376     }
2377 
2378     if (config->program_name == NULL) {
2379         status = config_init_program_name(config);
2380         if (_PyStatus_EXCEPTION(status)) {
2381             return status;
2382         }
2383     }
2384 
2385     if (config->parse_argv) {
2386         Py_ssize_t opt_index;
2387         status = config_parse_cmdline(config, &cmdline_warnoptions, &opt_index);
2388         if (_PyStatus_EXCEPTION(status)) {
2389             goto done;
2390         }
2391 
2392         status = config_run_filename_abspath(config);
2393         if (_PyStatus_EXCEPTION(status)) {
2394             goto done;
2395         }
2396 
2397         status = config_update_argv(config, opt_index);
2398         if (_PyStatus_EXCEPTION(status)) {
2399             goto done;
2400         }
2401     }
2402     else {
2403         status = config_run_filename_abspath(config);
2404         if (_PyStatus_EXCEPTION(status)) {
2405             goto done;
2406         }
2407     }
2408 
2409     if (config->use_environment) {
2410         status = config_init_env_warnoptions(config, &env_warnoptions);
2411         if (_PyStatus_EXCEPTION(status)) {
2412             goto done;
2413         }
2414     }
2415 
2416     /* Handle early PySys_AddWarnOption() calls */
2417     status = _PySys_ReadPreinitWarnOptions(&sys_warnoptions);
2418     if (_PyStatus_EXCEPTION(status)) {
2419         goto done;
2420     }
2421 
2422     status = config_init_warnoptions(config,
2423                                      &cmdline_warnoptions,
2424                                      &env_warnoptions,
2425                                      &sys_warnoptions);
2426     if (_PyStatus_EXCEPTION(status)) {
2427         goto done;
2428     }
2429 
2430     status = _PyStatus_OK();
2431 
2432 done:
2433     _PyWideStringList_Clear(&cmdline_warnoptions);
2434     _PyWideStringList_Clear(&env_warnoptions);
2435     _PyWideStringList_Clear(&sys_warnoptions);
2436     return status;
2437 }
2438 
2439 
2440 PyStatus
_PyConfig_SetPyArgv(PyConfig * config,const _PyArgv * args)2441 _PyConfig_SetPyArgv(PyConfig *config, const _PyArgv *args)
2442 {
2443     PyStatus status = _Py_PreInitializeFromConfig(config, args);
2444     if (_PyStatus_EXCEPTION(status)) {
2445         return status;
2446     }
2447 
2448     return _PyArgv_AsWstrList(args, &config->argv);
2449 }
2450 
2451 
2452 /* Set config.argv: decode argv using Py_DecodeLocale(). Pre-initialize Python
2453    if needed to ensure that encodings are properly configured. */
2454 PyStatus
PyConfig_SetBytesArgv(PyConfig * config,Py_ssize_t argc,char * const * argv)2455 PyConfig_SetBytesArgv(PyConfig *config, Py_ssize_t argc, char * const *argv)
2456 {
2457     _PyArgv args = {
2458         .argc = argc,
2459         .use_bytes_argv = 1,
2460         .bytes_argv = argv,
2461         .wchar_argv = NULL};
2462     return _PyConfig_SetPyArgv(config, &args);
2463 }
2464 
2465 
2466 PyStatus
PyConfig_SetArgv(PyConfig * config,Py_ssize_t argc,wchar_t * const * argv)2467 PyConfig_SetArgv(PyConfig *config, Py_ssize_t argc, wchar_t * const *argv)
2468 {
2469     _PyArgv args = {
2470         .argc = argc,
2471         .use_bytes_argv = 0,
2472         .bytes_argv = NULL,
2473         .wchar_argv = argv};
2474     return _PyConfig_SetPyArgv(config, &args);
2475 }
2476 
2477 
2478 PyStatus
PyConfig_SetWideStringList(PyConfig * config,PyWideStringList * list,Py_ssize_t length,wchar_t ** items)2479 PyConfig_SetWideStringList(PyConfig *config, PyWideStringList *list,
2480                            Py_ssize_t length, wchar_t **items)
2481 {
2482     PyStatus status = _Py_PreInitializeFromConfig(config, NULL);
2483     if (_PyStatus_EXCEPTION(status)) {
2484         return status;
2485     }
2486 
2487     PyWideStringList list2 = {.length = length, .items = items};
2488     if (_PyWideStringList_Copy(list, &list2) < 0) {
2489         return _PyStatus_NO_MEMORY();
2490     }
2491     return _PyStatus_OK();
2492 }
2493 
2494 
2495 /* Read the configuration into PyConfig from:
2496 
2497    * Command line arguments
2498    * Environment variables
2499    * Py_xxx global configuration variables
2500 
2501    The only side effects are to modify config and to call _Py_SetArgcArgv(). */
2502 PyStatus
PyConfig_Read(PyConfig * config)2503 PyConfig_Read(PyConfig *config)
2504 {
2505     PyStatus status;
2506 
2507     status = _Py_PreInitializeFromConfig(config, NULL);
2508     if (_PyStatus_EXCEPTION(status)) {
2509         return status;
2510     }
2511 
2512     config_get_global_vars(config);
2513 
2514     if (config->_orig_argv.length == 0
2515         && !(config->argv.length == 1
2516              && wcscmp(config->argv.items[0], L"") == 0))
2517     {
2518         if (_PyWideStringList_Copy(&config->_orig_argv, &config->argv) < 0) {
2519             return _PyStatus_NO_MEMORY();
2520         }
2521     }
2522 
2523     _PyPreCmdline precmdline = _PyPreCmdline_INIT;
2524     status = core_read_precmdline(config, &precmdline);
2525     if (_PyStatus_EXCEPTION(status)) {
2526         goto done;
2527     }
2528 
2529     assert(config->isolated >= 0);
2530     if (config->isolated) {
2531         config->use_environment = 0;
2532         config->user_site_directory = 0;
2533     }
2534 
2535     status = config_read_cmdline(config);
2536     if (_PyStatus_EXCEPTION(status)) {
2537         goto done;
2538     }
2539 
2540     /* Handle early PySys_AddXOption() calls */
2541     status = _PySys_ReadPreinitXOptions(config);
2542     if (_PyStatus_EXCEPTION(status)) {
2543         goto done;
2544     }
2545 
2546     status = config_read(config);
2547     if (_PyStatus_EXCEPTION(status)) {
2548         goto done;
2549     }
2550 
2551     /* Check config consistency */
2552     assert(config->isolated >= 0);
2553     assert(config->use_environment >= 0);
2554     assert(config->dev_mode >= 0);
2555     assert(config->_use_peg_parser >= 0);
2556     assert(config->install_signal_handlers >= 0);
2557     assert(config->use_hash_seed >= 0);
2558     assert(config->faulthandler >= 0);
2559     assert(config->tracemalloc >= 0);
2560     assert(config->site_import >= 0);
2561     assert(config->bytes_warning >= 0);
2562     assert(config->inspect >= 0);
2563     assert(config->interactive >= 0);
2564     assert(config->optimization_level >= 0);
2565     assert(config->parser_debug >= 0);
2566     assert(config->write_bytecode >= 0);
2567     assert(config->verbose >= 0);
2568     assert(config->quiet >= 0);
2569     assert(config->user_site_directory >= 0);
2570     assert(config->parse_argv >= 0);
2571     assert(config->configure_c_stdio >= 0);
2572     assert(config->buffered_stdio >= 0);
2573     assert(config->program_name != NULL);
2574     assert(_PyWideStringList_CheckConsistency(&config->argv));
2575     /* sys.argv must be non-empty: empty argv is replaced with [''] */
2576     assert(config->argv.length >= 1);
2577     assert(_PyWideStringList_CheckConsistency(&config->xoptions));
2578     assert(_PyWideStringList_CheckConsistency(&config->warnoptions));
2579     assert(_PyWideStringList_CheckConsistency(&config->module_search_paths));
2580     if (config->_install_importlib) {
2581         assert(config->module_search_paths_set != 0);
2582         /* don't check config->module_search_paths */
2583         assert(config->executable != NULL);
2584         assert(config->base_executable != NULL);
2585         assert(config->prefix != NULL);
2586         assert(config->base_prefix != NULL);
2587         assert(config->exec_prefix != NULL);
2588         assert(config->base_exec_prefix != NULL);
2589     }
2590     assert(config->platlibdir != NULL);
2591     assert(config->filesystem_encoding != NULL);
2592     assert(config->filesystem_errors != NULL);
2593     assert(config->stdio_encoding != NULL);
2594     assert(config->stdio_errors != NULL);
2595 #ifdef MS_WINDOWS
2596     assert(config->legacy_windows_stdio >= 0);
2597 #endif
2598     /* -c and -m options are exclusive */
2599     assert(!(config->run_command != NULL && config->run_module != NULL));
2600     assert(config->check_hash_pycs_mode != NULL);
2601     assert(config->_install_importlib >= 0);
2602     assert(config->pathconfig_warnings >= 0);
2603     assert(_PyWideStringList_CheckConsistency(&config->_orig_argv));
2604 
2605     status = _PyStatus_OK();
2606 
2607 done:
2608     _PyPreCmdline_Clear(&precmdline);
2609     return status;
2610 }
2611 
2612 
2613 PyObject*
_Py_GetConfigsAsDict(void)2614 _Py_GetConfigsAsDict(void)
2615 {
2616     PyObject *result = NULL;
2617     PyObject *dict = NULL;
2618 
2619     result = PyDict_New();
2620     if (result == NULL) {
2621         goto error;
2622     }
2623 
2624     /* global result */
2625     dict = _Py_GetGlobalVariablesAsDict();
2626     if (dict == NULL) {
2627         goto error;
2628     }
2629     if (PyDict_SetItemString(result, "global_config", dict) < 0) {
2630         goto error;
2631     }
2632     Py_CLEAR(dict);
2633 
2634     /* pre config */
2635     PyThreadState *tstate = _PyThreadState_GET();
2636     const PyPreConfig *pre_config = &tstate->interp->runtime->preconfig;
2637     dict = _PyPreConfig_AsDict(pre_config);
2638     if (dict == NULL) {
2639         goto error;
2640     }
2641     if (PyDict_SetItemString(result, "pre_config", dict) < 0) {
2642         goto error;
2643     }
2644     Py_CLEAR(dict);
2645 
2646     /* core config */
2647     const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
2648     dict = config_as_dict(config);
2649     if (dict == NULL) {
2650         goto error;
2651     }
2652     if (PyDict_SetItemString(result, "config", dict) < 0) {
2653         goto error;
2654     }
2655     Py_CLEAR(dict);
2656 
2657     return result;
2658 
2659 error:
2660     Py_XDECREF(result);
2661     Py_XDECREF(dict);
2662     return NULL;
2663 }
2664 
2665 
2666 static void
init_dump_ascii_wstr(const wchar_t * str)2667 init_dump_ascii_wstr(const wchar_t *str)
2668 {
2669     if (str == NULL) {
2670         PySys_WriteStderr("(not set)");
2671         return;
2672     }
2673 
2674     PySys_WriteStderr("'");
2675     for (; *str != L'\0'; str++) {
2676         unsigned int ch = (unsigned int)*str;
2677         if (ch == L'\'') {
2678             PySys_WriteStderr("\\'");
2679         } else if (0x20 <= ch && ch < 0x7f) {
2680             PySys_WriteStderr("%c", ch);
2681         }
2682         else if (ch <= 0xff) {
2683             PySys_WriteStderr("\\x%02x", ch);
2684         }
2685 #if SIZEOF_WCHAR_T > 2
2686         else if (ch > 0xffff) {
2687             PySys_WriteStderr("\\U%08x", ch);
2688         }
2689 #endif
2690         else {
2691             PySys_WriteStderr("\\u%04x", ch);
2692         }
2693     }
2694     PySys_WriteStderr("'");
2695 }
2696 
2697 
2698 /* Dump the Python path configuration into sys.stderr */
2699 void
_Py_DumpPathConfig(PyThreadState * tstate)2700 _Py_DumpPathConfig(PyThreadState *tstate)
2701 {
2702     PyObject *exc_type, *exc_value, *exc_tb;
2703     _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
2704 
2705     PySys_WriteStderr("Python path configuration:\n");
2706 
2707 #define DUMP_CONFIG(NAME, FIELD) \
2708         do { \
2709             PySys_WriteStderr("  " NAME " = "); \
2710             init_dump_ascii_wstr(config->FIELD); \
2711             PySys_WriteStderr("\n"); \
2712         } while (0)
2713 
2714     const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
2715     DUMP_CONFIG("PYTHONHOME", home);
2716     DUMP_CONFIG("PYTHONPATH", pythonpath_env);
2717     DUMP_CONFIG("program name", program_name);
2718     PySys_WriteStderr("  isolated = %i\n", config->isolated);
2719     PySys_WriteStderr("  environment = %i\n", config->use_environment);
2720     PySys_WriteStderr("  user site = %i\n", config->user_site_directory);
2721     PySys_WriteStderr("  import site = %i\n", config->site_import);
2722 #undef DUMP_CONFIG
2723 
2724 #define DUMP_SYS(NAME) \
2725         do { \
2726             obj = PySys_GetObject(#NAME); \
2727             PySys_FormatStderr("  sys.%s = ", #NAME); \
2728             if (obj != NULL) { \
2729                 PySys_FormatStderr("%A", obj); \
2730             } \
2731             else { \
2732                 PySys_WriteStderr("(not set)"); \
2733             } \
2734             PySys_FormatStderr("\n"); \
2735         } while (0)
2736 
2737     PyObject *obj;
2738     DUMP_SYS(_base_executable);
2739     DUMP_SYS(base_prefix);
2740     DUMP_SYS(base_exec_prefix);
2741     DUMP_SYS(platlibdir);
2742     DUMP_SYS(executable);
2743     DUMP_SYS(prefix);
2744     DUMP_SYS(exec_prefix);
2745 #undef DUMP_SYS
2746 
2747     PyObject *sys_path = PySys_GetObject("path");  /* borrowed reference */
2748     if (sys_path != NULL && PyList_Check(sys_path)) {
2749         PySys_WriteStderr("  sys.path = [\n");
2750         Py_ssize_t len = PyList_GET_SIZE(sys_path);
2751         for (Py_ssize_t i=0; i < len; i++) {
2752             PyObject *path = PyList_GET_ITEM(sys_path, i);
2753             PySys_FormatStderr("    %A,\n", path);
2754         }
2755         PySys_WriteStderr("  ]\n");
2756     }
2757 
2758     _PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
2759 }
2760