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