Coverage Report

Created: 2026-10-17 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/initconfig.c
Line
Count
Source
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_GetRaisedException()
9
#include "pycore_pylifecycle.h"   // _Py_PreInitializeFromConfig()
10
#include "pycore_pymem.h"         // _PyMem_DefaultRawMalloc()
11
#include "pycore_pyhash.h"        // _Py_HashSecret
12
#include "pycore_pystate.h"       // _PyThreadState_GET()
13
#include "pycore_pystats.h"       // _Py_StatsOn()
14
#include "pycore_sysmodule.h"     // _PySys_SetIntMaxStrDigits()
15
16
#include "osdefs.h"               // DELIM
17
18
#include <locale.h>               // setlocale()
19
#include <stdlib.h>               // getenv()
20
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
21
#  ifdef HAVE_IO_H
22
#    include <io.h>
23
#  endif
24
#  ifdef HAVE_FCNTL_H
25
#    include <fcntl.h>            // O_BINARY
26
#  endif
27
#endif
28
29
#ifdef __APPLE__
30
/* Enable system log by default on non-macOS Apple platforms */
31
#  if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
32
#define USE_SYSTEM_LOGGER_DEFAULT 1;
33
#  else
34
#define USE_SYSTEM_LOGGER_DEFAULT 0;
35
#  endif
36
#endif
37
38
#include "config_common.h"
39
40
/* --- PyConfig setters ------------------------------------------- */
41
42
typedef PyObject* (*config_sys_flag_setter) (int value);
43
44
static PyObject*
45
config_sys_flag_long(int value)
46
0
{
47
0
    return PyLong_FromLong(value);
48
0
}
49
50
static PyObject*
51
config_sys_flag_not(int value)
52
0
{
53
0
    value = (!value);
54
0
    return config_sys_flag_long(value);
55
0
}
56
57
/* --- PyConfig spec ---------------------------------------------- */
58
59
typedef enum {
60
    PyConfig_MEMBER_INT = 0,
61
    PyConfig_MEMBER_UINT = 1,
62
    PyConfig_MEMBER_ULONG = 2,
63
    PyConfig_MEMBER_BOOL = 3,
64
65
    PyConfig_MEMBER_WSTR = 10,
66
    PyConfig_MEMBER_WSTR_OPT = 11,
67
    PyConfig_MEMBER_WSTR_LIST = 12,
68
} PyConfigMemberType;
69
70
typedef enum {
71
    // Option which cannot be get or set by PyConfig_Get() and PyConfig_Set()
72
    PyConfig_MEMBER_INIT_ONLY = 0,
73
74
    // Option which cannot be set by PyConfig_Set()
75
    PyConfig_MEMBER_READ_ONLY = 1,
76
77
    // Public option: can be get and set by PyConfig_Get() and PyConfig_Set()
78
    PyConfig_MEMBER_PUBLIC = 2,
79
} PyConfigMemberVisibility;
80
81
typedef struct {
82
    const char *attr;
83
    int flag_index;
84
    config_sys_flag_setter flag_setter;
85
} PyConfigSysSpec;
86
87
typedef struct {
88
    int *ptr;
89
    int not;
90
} PyConfigGlobalVar;
91
92
typedef struct {
93
    const char *name;
94
    size_t offset;
95
    PyConfigMemberType type;
96
    PyConfigMemberVisibility visibility;
97
    PyConfigSysSpec sys;
98
} PyConfigSpec;
99
100
#define SPEC(MEMBER, TYPE, VISIBILITY, sys) \
101
    {#MEMBER, offsetof(PyConfig, MEMBER), \
102
     PyConfig_MEMBER_##TYPE, PyConfig_MEMBER_##VISIBILITY, sys}
103
104
#define SYS_ATTR(name) {name, -1, NULL}
105
#define SYS_FLAG_SETTER(index, setter) {NULL, index, setter}
106
#define SYS_FLAG(index) SYS_FLAG_SETTER(index, NULL)
107
#define NO_SYS SYS_ATTR(NULL)
108
109
// Update _test_embed_set_config when adding new members
110
static const PyConfigSpec PYCONFIG_SPEC[] = {
111
    // --- Public options -----------
112
113
    SPEC(argv, WSTR_LIST, PUBLIC, SYS_ATTR("argv")),
114
    SPEC(base_exec_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("base_exec_prefix")),
115
    SPEC(base_executable, WSTR_OPT, PUBLIC, SYS_ATTR("_base_executable")),
116
    SPEC(base_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("base_prefix")),
117
    SPEC(bytes_warning, UINT, PUBLIC, SYS_FLAG(9)),
118
    SPEC(cpu_count, INT, PUBLIC, NO_SYS),
119
    SPEC(lazy_imports, INT, PUBLIC, NO_SYS),
120
    SPEC(exec_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("exec_prefix")),
121
    SPEC(executable, WSTR_OPT, PUBLIC, SYS_ATTR("executable")),
122
    SPEC(inspect, BOOL, PUBLIC, SYS_FLAG(1)),
123
    SPEC(int_max_str_digits, UINT, PUBLIC, NO_SYS),
124
    SPEC(interactive, BOOL, PUBLIC, SYS_FLAG(2)),
125
    SPEC(module_search_paths, WSTR_LIST, PUBLIC, SYS_ATTR("path")),
126
    SPEC(optimization_level, UINT, PUBLIC, SYS_FLAG(3)),
127
    SPEC(parser_debug, BOOL, PUBLIC, SYS_FLAG(0)),
128
    SPEC(platlibdir, WSTR, PUBLIC, SYS_ATTR("platlibdir")),
129
    SPEC(prefix, WSTR_OPT, PUBLIC, SYS_ATTR("prefix")),
130
    SPEC(pycache_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("pycache_prefix")),
131
    SPEC(quiet, BOOL, PUBLIC, SYS_FLAG(10)),
132
    SPEC(stdlib_dir, WSTR_OPT, PUBLIC, SYS_ATTR("_stdlib_dir")),
133
    SPEC(use_environment, BOOL, PUBLIC,
134
         SYS_FLAG_SETTER(7, config_sys_flag_not)),
135
    SPEC(verbose, UINT, PUBLIC, SYS_FLAG(8)),
136
    SPEC(warnoptions, WSTR_LIST, PUBLIC, SYS_ATTR("warnoptions")),
137
    SPEC(write_bytecode, BOOL, PUBLIC, SYS_FLAG_SETTER(4, config_sys_flag_not)),
138
    SPEC(xoptions, WSTR_LIST, PUBLIC, SYS_ATTR("_xoptions")),
139
140
    // --- Read-only options -----------
141
142
#ifdef Py_STATS
143
    SPEC(_pystats, BOOL, READ_ONLY, NO_SYS),
144
#endif
145
    SPEC(buffered_stdio, BOOL, READ_ONLY, NO_SYS),
146
    SPEC(check_hash_pycs_mode, WSTR, READ_ONLY, NO_SYS),
147
    SPEC(code_debug_ranges, BOOL, READ_ONLY, NO_SYS),
148
    SPEC(configure_c_stdio, BOOL, READ_ONLY, NO_SYS),
149
    SPEC(dev_mode, BOOL, READ_ONLY, NO_SYS),  // sys.flags.dev_mode
150
    SPEC(dump_refs, BOOL, READ_ONLY, NO_SYS),
151
    SPEC(dump_refs_file, WSTR_OPT, READ_ONLY, NO_SYS),
152
#ifdef Py_GIL_DISABLED
153
    SPEC(enable_gil, INT, READ_ONLY, NO_SYS),
154
    SPEC(tlbc_enabled, INT, READ_ONLY, NO_SYS),
155
#endif
156
    SPEC(faulthandler, BOOL, READ_ONLY, NO_SYS),
157
    SPEC(filesystem_encoding, WSTR, READ_ONLY, NO_SYS),
158
    SPEC(filesystem_errors, WSTR, READ_ONLY, NO_SYS),
159
    SPEC(hash_seed, ULONG, READ_ONLY, NO_SYS),
160
    SPEC(home, WSTR_OPT, READ_ONLY, NO_SYS),
161
    SPEC(thread_inherit_context, INT, READ_ONLY, NO_SYS),
162
    SPEC(context_aware_warnings, INT, READ_ONLY, NO_SYS),
163
    SPEC(import_time, UINT, READ_ONLY, NO_SYS),
164
    SPEC(install_signal_handlers, BOOL, READ_ONLY, NO_SYS),
165
    SPEC(isolated, BOOL, READ_ONLY, NO_SYS),  // sys.flags.isolated
166
#ifdef MS_WINDOWS
167
    SPEC(legacy_windows_stdio, BOOL, READ_ONLY, NO_SYS),
168
#endif
169
    SPEC(malloc_stats, BOOL, READ_ONLY, NO_SYS),
170
    SPEC(pymalloc_hugepages, BOOL, READ_ONLY, NO_SYS),
171
    SPEC(orig_argv, WSTR_LIST, READ_ONLY, SYS_ATTR("orig_argv")),
172
    SPEC(parse_argv, BOOL, READ_ONLY, NO_SYS),
173
    SPEC(pathconfig_warnings, BOOL, READ_ONLY, NO_SYS),
174
    SPEC(perf_profiling, UINT, READ_ONLY, NO_SYS),
175
    SPEC(remote_debug, BOOL, READ_ONLY, NO_SYS),
176
    SPEC(program_name, WSTR, READ_ONLY, NO_SYS),
177
    SPEC(run_command, WSTR_OPT, READ_ONLY, NO_SYS),
178
    SPEC(run_filename, WSTR_OPT, READ_ONLY, NO_SYS),
179
    SPEC(run_module, WSTR_OPT, READ_ONLY, NO_SYS),
180
#ifdef Py_DEBUG
181
    SPEC(run_presite, WSTR_OPT, READ_ONLY, NO_SYS),
182
#endif
183
    SPEC(safe_path, BOOL, READ_ONLY, NO_SYS),
184
    SPEC(show_ref_count, BOOL, READ_ONLY, NO_SYS),
185
    SPEC(site_import, BOOL, READ_ONLY, NO_SYS),  // sys.flags.no_site
186
    SPEC(skip_source_first_line, BOOL, READ_ONLY, NO_SYS),
187
    SPEC(stdio_encoding, WSTR_OPT, READ_ONLY, NO_SYS),
188
    SPEC(stdio_errors, WSTR, READ_ONLY, NO_SYS),
189
    SPEC(tracemalloc, UINT, READ_ONLY, NO_SYS),
190
    SPEC(use_frozen_modules, BOOL, READ_ONLY, NO_SYS),
191
    SPEC(use_hash_seed, BOOL, READ_ONLY, NO_SYS),
192
#ifdef __APPLE__
193
    SPEC(use_system_logger, BOOL, READ_ONLY, NO_SYS),
194
#endif
195
    SPEC(user_site_directory, BOOL, READ_ONLY, NO_SYS),  // sys.flags.no_user_site
196
    SPEC(warn_default_encoding, BOOL, READ_ONLY, NO_SYS),
197
198
    // --- Init-only options -----------
199
200
    SPEC(_config_init, UINT, INIT_ONLY, NO_SYS),
201
    SPEC(_init_main, BOOL, INIT_ONLY, NO_SYS),
202
    SPEC(_install_importlib, BOOL, INIT_ONLY, NO_SYS),
203
    SPEC(_is_python_build, BOOL, INIT_ONLY, NO_SYS),
204
    SPEC(module_search_paths_set, BOOL, INIT_ONLY, NO_SYS),
205
    SPEC(pythonpath_env, WSTR_OPT, INIT_ONLY, NO_SYS),
206
    SPEC(sys_path_0, WSTR_OPT, INIT_ONLY, NO_SYS),
207
    SPEC(_deferred_cmdline_option, INT, INIT_ONLY, NO_SYS),
208
209
    // Array terminator
210
    {NULL, 0, 0, 0, NO_SYS},
211
};
212
213
#undef SPEC
214
#define SPEC(MEMBER, TYPE, VISIBILITY) \
215
    {#MEMBER, offsetof(PyPreConfig, MEMBER), PyConfig_MEMBER_##TYPE, \
216
     PyConfig_MEMBER_##VISIBILITY, NO_SYS}
217
218
static const PyConfigSpec PYPRECONFIG_SPEC[] = {
219
    // --- Read-only options -----------
220
221
    SPEC(allocator, INT, READ_ONLY),
222
    SPEC(coerce_c_locale, BOOL, READ_ONLY),
223
    SPEC(coerce_c_locale_warn, BOOL, READ_ONLY),
224
    SPEC(configure_locale, BOOL, READ_ONLY),
225
#ifdef MS_WINDOWS
226
    SPEC(legacy_windows_fs_encoding, BOOL, READ_ONLY),
227
#endif
228
    SPEC(utf8_mode, BOOL, READ_ONLY),
229
230
    // --- Init-only options -----------
231
    // Members already present in PYCONFIG_SPEC
232
233
    SPEC(_config_init, INT, INIT_ONLY),
234
    SPEC(dev_mode, BOOL, INIT_ONLY),
235
    SPEC(isolated, BOOL, INIT_ONLY),
236
    SPEC(parse_argv, BOOL, INIT_ONLY),
237
    SPEC(use_environment, BOOL, INIT_ONLY),
238
239
    // Array terminator
240
    {NULL, 0, 0, 0, NO_SYS},
241
};
242
243
#undef SPEC
244
#undef SYS_ATTR
245
#undef SYS_FLAG_SETTER
246
#undef SYS_FLAG
247
#undef NO_SYS
248
249
250
// Forward declarations
251
static PyObject* config_get(const PyConfig *config, const PyConfigSpec *spec,
252
                            int use_sys);
253
static void initconfig_free_wstr(wchar_t *member);
254
static void initconfig_free_wstr_list(PyWideStringList *list);
255
static void initconfig_free_config(const PyConfig *config);
256
257
258
/* --- Command line options --------------------------------------- */
259
260
/*
261
 * Help text markup (matching Lib/_colorize.py Argparse theme).
262
 *
263
 * Color spans, #X{...}  where "}" resets to default color:
264
 *   #b{...}  label              bold yellow
265
 *   #B{...}  summary label      yellow
266
 *   #E{...}  env var (primary)  bold cyan
267
 *   #e{...}  env var reference  cyan
268
 *   #h{...}  heading            bold blue
269
 *   #L{...}  long option        bold cyan
270
 *   #s{...}  short option       bold green
271
 *   #S{...}  summary short opt  green
272
 *
273
 * Runtime substitutions (no "{" follows):
274
 *   #P  program name (bold magenta)
275
 *   #D  path separator (DELIM)
276
 *   #H  PYTHONHOMEHELP default search path
277
 *
278
 * fprint_help() walks the string, expanding color codes only when colorize=1
279
 * and substituting runtime values regardless.
280
 */
281
282
#if defined(MS_WINDOWS)
283
#  define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
284
#else
285
0
#  define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
286
#endif
287
288
/* Determine if we can emit ANSI color codes on the given stream.
289
 * Logic mirrors Lib/_colorize.py:can_colorize(). */
290
static int
291
_Py_can_colorize(FILE *f)
292
0
{
293
0
    const char *env;
294
295
0
    env = Py_GETENV("PYTHON_COLORS");
296
0
    if (env) {
297
0
        if (strcmp(env, "0") == 0) {
298
0
            return 0;
299
0
        }
300
0
        if (strcmp(env, "1") == 0) {
301
0
            return 1;
302
0
        }
303
0
    }
304
0
    if (getenv("NO_COLOR")) {
305
0
        return 0;
306
0
    }
307
0
    if (getenv("FORCE_COLOR")) {
308
0
        return 1;
309
0
    }
310
0
    env = getenv("TERM");
311
0
    if (env && strcmp(env, "dumb") == 0) {
312
0
        return 0;
313
0
    }
314
#if defined(MS_WINDOWS) && defined(HAVE_WINDOWS_CONSOLE_IO)
315
    {
316
        DWORD mode = 0;
317
        DWORD nStdHandle = (f == stderr) ? STD_ERROR_HANDLE
318
                                         : STD_OUTPUT_HANDLE;
319
        HANDLE handle = GetStdHandle(nStdHandle);
320
        if (!GetConsoleMode(handle, &mode)
321
            || !(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
322
        {
323
            return 0;
324
        }
325
    }
326
#endif
327
0
    return isatty(fileno(f));
328
0
}
329
330
/* Walk help text, expanding markup:
331
 *   #X{...}  color span (only emitted when colorize=1; '}' resets).
332
 *   #X       runtime substitution (program name, DELIM, PYTHONHOMEHELP).
333
 * See the markup table above the macro/comment block. */
334
static void
335
fprint_help(FILE *f, const char *text, int colorize, const wchar_t *program)
336
0
{
337
0
    for (const char *p = text; *p; ) {
338
0
        if (*p == '#' && p[1]) {
339
0
            char code = p[1];
340
0
            if (p[2] == '{') {
341
                /* Color span open */
342
0
                const char *seq = NULL;
343
0
                switch (code) {
344
0
                case 'h': seq = "\x1b[1;34m"; break;  // heading
345
0
                case 'E': seq = "\x1b[1;36m"; break;  // env var primary
346
0
                case 'e': seq = "\x1b[36m";   break;  // env var reference
347
0
                case 'L': seq = "\x1b[1;36m"; break;  // long option
348
0
                case 'b': seq = "\x1b[1;33m"; break;  // label
349
0
                case 'B': seq = "\x1b[33m";   break;  // summary label
350
0
                case 's': seq = "\x1b[1;32m"; break;  // short option
351
0
                case 'S': seq = "\x1b[32m";   break;  // summary short option
352
0
                }
353
0
                if (colorize && seq) fputs(seq, f);
354
0
                p += 3;  // skip "#X{"
355
0
                continue;
356
0
            }
357
            /* Runtime substitution */
358
0
            switch (code) {
359
0
            case 'P':  // program name with bold magenta
360
0
                if (colorize) fputs("\x1b[1;35m", f);
361
0
                if (program) fprintf(f, "%ls", program);
362
0
                if (colorize) fputs("\x1b[0m", f);
363
0
                break;
364
0
            case 'D':
365
0
                fputc((char)DELIM, f);
366
0
                break;
367
0
            case 'H':
368
0
                fputs(PYTHONHOMEHELP, f);
369
0
                break;
370
0
            default:  // unknown: emit literally
371
0
                fputc('#', f);
372
0
                fputc(code, f);
373
0
                break;
374
0
            }
375
0
            p += 2;  // skip "#X"
376
0
            continue;
377
0
        }
378
0
        if (*p == '}') {
379
0
            if (colorize) fputs("\x1b[0m", f);
380
0
            p++;
381
0
            continue;
382
0
        }
383
0
        fputc(*p++, f);
384
0
    }
385
0
}
386
387
/* Short usage message */
388
static const char usage_line[] =
389
"#h{usage:} #P [#S{option}] #S{...} "
390
"[#S{-c} #B{cmd} | #S{-m} #B{mod} | #S{file} | #S{-}] "
391
"[#S{arg}] #S{...}\n"
392
;
393
394
/* Long help message */
395
/* Lines sorted by option name; keep in sync with usage_envvars* below */
396
static const char usage_help[] =
397
"#h{Options (and corresponding environment variables):}\n"
398
"#s{-b}     : issue warnings about converting bytes/bytearray to str and comparing\n"
399
"         bytes/bytearray with str or bytes with int. (#S{-bb}: issue errors)\n"
400
"         deprecated since 3.15 and will become no-op in 3.17.\n"
401
"#s{-B}     : don't write .pyc files on import; also #e{PYTHONDONTWRITEBYTECODE}#B{=x}\n"
402
"#s{-c} #b{cmd} : program passed in as string (terminates option list)\n"
403
"#s{-d}     : turn on parser debugging output (for experts only, only works on\n"
404
"         debug builds); also #e{PYTHONDEBUG}#B{=x}\n"
405
"#s{-E}     : ignore #e{PYTHON*} environment variables (such as #e{PYTHONPATH})\n"
406
"#s{-h}     : print this help message and exit (also #S{-?} or #e{--help})\n"
407
"#s{-i}     : inspect interactively after running script; forces a prompt even\n"
408
"         if stdin does not appear to be a terminal; also #e{PYTHONINSPECT}#B{=x}\n"
409
"#s{-I}     : isolate Python from the user's environment (implies #S{-E}, #S{-P} and #S{-s})\n"
410
"#s{-m} #b{mod} : run library module as a script (terminates option list)\n"
411
"#s{-O}     : remove assert and __debug__-dependent statements; add .opt-1 before\n"
412
"         .pyc extension; also #e{PYTHONOPTIMIZE}#B{=x}\n"
413
"#s{-OO}    : do #S{-O} changes and also discard docstrings; add .opt-2 before\n"
414
"         .pyc extension\n"
415
"#s{-P}     : don't prepend a potentially unsafe path to sys.path; also\n"
416
"         #e{PYTHONSAFEPATH}\n"
417
"#s{-q}     : don't print version and copyright messages on interactive startup\n"
418
"#s{-s}     : don't add user site directory to sys.path; also #e{PYTHONNOUSERSITE}#B{=x}\n"
419
"#s{-S}     : don't imply 'import site' on initialization\n"
420
"#s{-u}     : force the stdout and stderr streams to be unbuffered;\n"
421
"         this option has no effect on stdin; also #e{PYTHONUNBUFFERED}#B{=x}\n"
422
"#s{-v}     : verbose (trace import statements); also #e{PYTHONVERBOSE}#B{=x}\n"
423
"         can be supplied multiple times to increase verbosity\n"
424
"#s{-V}     : print the Python version number and exit (also #e{--version})\n"
425
"         when given twice, print more information about the build\n"
426
"#s{-W} #b{arg} : warning control; #B{arg} is action:message:category:module:lineno\n"
427
"         also #e{PYTHONWARNINGS}#B{=arg}\n"
428
"#s{-x}     : skip first line of source, allowing use of non-Unix forms of #!cmd\n"
429
"#s{-X} #b{opt} : set implementation-specific option\n"
430
"#L{--check-hash-based-pycs} #b{always|default|never}:\n"
431
"         control how Python invalidates hash-based .pyc files\n"
432
"#L{--help-env}: print help about Python environment variables and exit\n"
433
"#L{--help-xoptions}: print help about implementation-specific #S{-X} options and exit\n"
434
"#L{--help-all}: print complete help information and exit\n"
435
"\n"
436
"#h{Arguments:}\n"
437
"#s{file}   : program read from script file\n"
438
"#s{-}      : program read from stdin (default; interactive mode if a tty)\n"
439
"#s{arg} #b{...}: arguments passed to program in sys.argv[1:]\n"
440
;
441
442
static const char usage_xoptions[] =
443
"#h{The following implementation-specific options are available:}\n"
444
"#s{-X} #L{context_aware_warnings}#b{=[0|1]}: if true (#B{1}) then the warnings module will\n"
445
"         use a context variables; if false (#B{0}) then the warnings module will\n"
446
"         use module globals, which is not concurrent-safe; set to true for\n"
447
"         free-threaded builds and false otherwise; also\n"
448
"         #e{PYTHON_CONTEXT_AWARE_WARNINGS}\n"
449
"#s{-X} #L{cpu_count}#b{=N}: override the return value of os.cpu_count();\n"
450
"         #S{-X} #e{cpu_count}#B{=default} cancels overriding; also #e{PYTHON_CPU_COUNT}\n"
451
"#s{-X} #L{dev} : enable Python Development Mode; also #e{PYTHONDEVMODE}\n"
452
"#s{-X} #L{disable-remote-debug}: disable remote debugging; also #e{PYTHON_DISABLE_REMOTE_DEBUG}\n"
453
"#s{-X} #L{faulthandler}: dump the Python traceback on fatal errors;\n"
454
"         also #e{PYTHONFAULTHANDLER}\n"
455
"#s{-X} #L{frozen_modules}#b{=[on|off]}: whether to use frozen modules; the default is \"#B{on}\"\n"
456
"         for installed Python and \"#B{off}\" for a local build;\n"
457
"         also #e{PYTHON_FROZEN_MODULES}\n"
458
#ifdef Py_GIL_DISABLED
459
"#s{-X} #L{gil}#b{=[0|1]}: enable (#B{1}) or disable (#B{0}) the GIL; also #e{PYTHON_GIL}\n"
460
#endif
461
"#s{-X} #L{importtime}#b{[=2]}: show how long each import takes; use #S{-X} #e{importtime}#B{=2} to\n"
462
"         log imports of already-loaded modules; also #e{PYTHONPROFILEIMPORTTIME}\n"
463
"#s{-X} #L{int_max_str_digits}#b{=N}: limit the size of int<->str conversions;\n"
464
"         0 disables the limit; also #e{PYTHONINTMAXSTRDIGITS}\n"
465
"#s{-X} #L{lazy_imports}#b{=[all|normal]}: control global lazy imports;\n"
466
"         default is #B{normal}; also #e{PYTHON_LAZY_IMPORTS}\n"
467
"#s{-X} #L{no_debug_ranges}: don't include extra location information in code objects;\n"
468
"         also #e{PYTHONNODEBUGRANGES}\n"
469
"#s{-X} #L{pathconfig_warnings}#b{=[0|1]}: if true (#B{1}) then path configuration is allowed\n"
470
"         to log warnings into stderr; if false (#B{0}) suppress these warnings;\n"
471
"         set to true by default; also #e{PYTHON_PATHCONFIG_WARNINGS}\n"
472
"#s{-X} #L{perf}: support the Linux \"perf\" profiler; also #e{PYTHONPERFSUPPORT}#B{=1}\n"
473
"#s{-X} #L{perf_jit}: support the Linux \"perf\" profiler with DWARF support;\n"
474
"         also #e{PYTHON_PERF_JIT_SUPPORT}#B{=1}\n"
475
#ifdef Py_DEBUG
476
"#s{-X} #L{presite}#b{=MOD}: import this module before site; also #e{PYTHON_PRESITE}\n"
477
#endif
478
"#s{-X} #L{pycache_prefix}#b{=PATH}: write .pyc files to a parallel tree instead of to the\n"
479
"         code tree; also #e{PYTHONPYCACHEPREFIX}\n"
480
#ifdef Py_STATS
481
"#s{-X} #L{pystats}: enable pystats collection at startup; also #e{PYTHONSTATS}\n"
482
#endif
483
"#s{-X} #L{showrefcount}: output the total reference count and number of used\n"
484
"         memory blocks when the program finishes or after each statement in\n"
485
"         the interactive interpreter; only works on debug builds\n"
486
"#s{-X} #L{thread_inherit_context}#b{=[0|1]}: enable (#B{1}) or disable (#B{0}) threads inheriting\n"
487
"         context vars by default; enabled by default in the free-threaded\n"
488
"         build and disabled otherwise; also #e{PYTHON_THREAD_INHERIT_CONTEXT}\n"
489
#ifdef Py_GIL_DISABLED
490
"#s{-X} #L{tlbc}#b{=[0|1]}: enable (#B{1}) or disable (#B{0}) thread-local bytecode. Also\n"
491
"         #e{PYTHON_TLBC}\n"
492
#endif
493
"#s{-X} #L{tracemalloc}#b{[=N]}: trace Python memory allocations; N sets a traceback limit\n"
494
"         of #B{N} frames (default: #B{1}); also #e{PYTHONTRACEMALLOC}#B{=N}\n"
495
"#s{-X} #L{utf8}#b{[=0|1]}: enable (#B{1}) or disable (#B{0}) UTF-8 mode; also #e{PYTHONUTF8}\n"
496
"#s{-X} #L{warn_default_encoding}: enable opt-in EncodingWarning for 'encoding=None';\n"
497
"         also #e{PYTHONWARNDEFAULTENCODING}\n"
498
;
499
500
/* Envvars that don't have equivalent command-line options are listed first */
501
static const char usage_envvars[] =
502
"#h{Environment variables that change behavior:}\n"
503
"#E{PYTHONASYNCIODEBUG}: enable asyncio debug mode\n"
504
"#E{PYTHON_BASIC_REPL}: use the traditional parser-based REPL\n"
505
"#E{PYTHONBREAKPOINT}: if this variable is set to #B{0}, it disables the default\n"
506
"                  debugger.  It can be set to the callable of your debugger of\n"
507
"                  choice.\n"
508
"#E{PYTHONCASEOK}    : ignore case in 'import' statements (Windows)\n"
509
"#E{PYTHONCOERCECLOCALE}: if this variable is set to #B{0}, it disables the locale\n"
510
"                  coercion behavior.  Use #e{PYTHONCOERCECLOCALE}#B{=warn} to request\n"
511
"                  display of locale coercion and locale compatibility warnings\n"
512
"                  on stderr.\n"
513
"#E{PYTHON_COLORS}   : if this variable is set to #B{1}, the interpreter will colorize\n"
514
"                  various kinds of output.  Setting it to #B{0} deactivates\n"
515
"                  this behavior.\n"
516
#ifdef Py_TRACE_REFS
517
"#E{PYTHONDUMPREFS}  : dump objects and reference counts still alive after shutdown\n"
518
"#E{PYTHONDUMPREFSFILE}: dump objects and reference counts to the specified file\n"
519
#endif
520
#ifdef __APPLE__
521
"#E{PYTHONEXECUTABLE}: set sys.argv[0] to this value (macOS only)\n"
522
#endif
523
"#E{PYTHONHASHSEED}  : if this variable is set to 'random', a random value is used\n"
524
"                  to seed the hashes of str and bytes objects.  It can also be\n"
525
"                  set to an integer in the range [0,4294967295] to get hash\n"
526
"                  values with a predictable seed.\n"
527
"#E{PYTHON_HISTORY}  : the location of a .python_history file.\n"
528
"#E{PYTHONHOME}      : alternate <prefix> directory (or <prefix>#D<exec_prefix>).\n"
529
"                  The default module search path uses #H.\n"
530
"#E{PYTHONIOENCODING}: encoding[:errors] used for stdin/stdout/stderr\n"
531
#ifdef MS_WINDOWS
532
"#E{PYTHONLEGACYWINDOWSFSENCODING}: use legacy \"mbcs\" encoding for file system\n"
533
"#E{PYTHONLEGACYWINDOWSSTDIO}: use legacy Windows stdio\n"
534
#endif
535
"#E{PYTHONMALLOC}    : set the Python memory allocators and/or install debug hooks\n"
536
"                  on Python memory allocators.  Use #e{PYTHONMALLOC}#B{=debug} to\n"
537
"                  install debug hooks.\n"
538
"#E{PYTHONMALLOCSTATS}: print memory allocator statistics\n"
539
"#E{PYTHONPATH}      : '#D'-separated list of directories prefixed to the\n"
540
"                  default module search path.  The result is sys.path.\n"
541
"#E{PYTHONPLATLIBDIR}: override sys.platlibdir\n"
542
"#E{PYTHONSTARTUP}   : file executed on interactive startup (no default)\n"
543
"#E{PYTHONUSERBASE}  : defines the user base directory (site.USER_BASE)\n"
544
"\n"
545
"#h{These variables have equivalent command-line options (see }#e{--help} for details):\n"
546
"#E{PYTHON_CONTEXT_AWARE_WARNINGS}: if true (#B{1}), enable thread-safe warnings\n"
547
"                  module behaviour (#S{-X} #e{context_aware_warnings})\n"
548
"#E{PYTHON_CPU_COUNT}: override the return value of os.cpu_count() (#S{-X} #e{cpu_count})\n"
549
"#E{PYTHONDEBUG}     : enable parser debug mode (#S{-d})\n"
550
"#E{PYTHONDEVMODE}   : enable Python Development Mode (#S{-X} #e{dev})\n"
551
"#E{PYTHONDONTWRITEBYTECODE}: don't write .pyc files (#S{-B})\n"
552
"#E{PYTHONFAULTHANDLER}: dump the Python traceback on fatal errors (#S{-X} #e{faulthandler})\n"
553
"#E{PYTHON_FROZEN_MODULES}: whether to use frozen modules; the default is \"#B{on}\"\n"
554
"                  for installed Python and \"#B{off}\" for a local build\n"
555
"                  (#S{-X} #e{frozen_modules})\n"
556
#ifdef Py_GIL_DISABLED
557
"#E{PYTHON_GIL}      : when set to #B{0}, disables the GIL (#S{-X} #e{gil})\n"
558
#endif
559
"#E{PYTHONINSPECT}   : inspect interactively after running script (#S{-i})\n"
560
"#E{PYTHONINTMAXSTRDIGITS}: limit the size of int<->str conversions;\n"
561
"                  0 disables the limit (#S{-X} #e{int_max_str_digits}#B{=N})\n"
562
"#E{PYTHON_LAZY_IMPORTS}: control global lazy imports (#S{-X} #e{lazy_imports})\n"
563
"#E{PYTHONNODEBUGRANGES}: don't include extra location information in code objects\n"
564
"                  (#S{-X} #e{no_debug_ranges})\n"
565
"#E{PYTHONNOUSERSITE}: disable user site directory (#S{-s})\n"
566
"#E{PYTHONOPTIMIZE}  : enable level 1 optimizations (#S{-O})\n"
567
"#E{PYTHON_PERF_JIT_SUPPORT}: enable Linux \"perf\" profiler support with JIT\n"
568
"                  (#S{-X} #e{perf_jit})\n"
569
"#E{PYTHONPERFSUPPORT}: support the Linux \"perf\" profiler (#S{-X} #e{perf})\n"
570
#ifdef Py_DEBUG
571
"#E{PYTHON_PRESITE}: import this module before site (#S{-X} #e{presite})\n"
572
#endif
573
"#E{PYTHONPROFILEIMPORTTIME}: show how long each import takes (#S{-X} #e{importtime})\n"
574
"#E{PYTHONPYCACHEPREFIX}: root directory for bytecode cache (pyc) files\n"
575
"                  (#S{-X} #e{pycache_prefix})\n"
576
"#E{PYTHONSAFEPATH}  : don't prepend a potentially unsafe path to sys.path.\n"
577
#ifdef Py_STATS
578
"#E{PYTHONSTATS}     : turns on statistics gathering (#S{-X} #e{pystats})\n"
579
#endif
580
"#E{PYTHON_THREAD_INHERIT_CONTEXT}: if true (#B{1}), threads inherit context vars\n"
581
"                  (#S{-X} #e{thread_inherit_context})\n"
582
#ifdef Py_GIL_DISABLED
583
"#E{PYTHON_TLBC}     : when set to #B{0}, disables thread-local bytecode (#S{-X} #e{tlbc})\n"
584
#endif
585
"#E{PYTHONTRACEMALLOC}: trace Python memory allocations (#S{-X} #e{tracemalloc})\n"
586
"#E{PYTHONUNBUFFERED}: disable stdout/stderr buffering (#S{-u})\n"
587
"#E{PYTHONUTF8}      : control the UTF-8 mode (#S{-X} #e{utf8})\n"
588
"#E{PYTHONVERBOSE}   : trace import statements (#S{-v})\n"
589
"#E{PYTHONWARNDEFAULTENCODING}: enable opt-in EncodingWarning for 'encoding=None'\n"
590
"                  (#S{-X} #e{warn_default_encoding})\n"
591
"#E{PYTHONWARNINGS}  : warning control (#S{-W})\n"
592
;
593
594
595
/* --- Global configuration variables ----------------------------- */
596
597
// Variable removed from Python limited C API 3.16, but kept in the stable ABI
598
PyAPI_DATA(int) Py_UTF8Mode;
599
600
/* UTF-8 mode (PEP 540): if equal to 1, use the UTF-8 encoding, and change
601
   stdin and stdout error handler to "surrogateescape". */
602
int Py_UTF8Mode = 0;
603
604
605
static PyObject *
606
_Py_GetGlobalVariablesAsDict(void)
607
0
{
608
0
    extern const char *Py_FileSystemDefaultEncoding;
609
0
    extern const char *Py_FileSystemDefaultEncodeErrors;
610
0
    extern int Py_HasFileSystemDefaultEncoding;
611
0
    extern int _Py_HasFileSystemDefaultEncodeErrors;
612
613
0
    PyObject *dict = PyDict_New();
614
0
    if (dict == NULL) {
615
0
        return NULL;
616
0
    }
617
618
0
#define SET_ITEM(KEY, EXPR) \
619
0
        do { \
620
0
            PyObject *obj = (EXPR); \
621
0
            if (obj == NULL) { \
622
0
                goto fail; \
623
0
            } \
624
0
            int res = PyDict_SetItemString(dict, (KEY), obj); \
625
0
            Py_DECREF(obj); \
626
0
            if (res < 0) { \
627
0
                goto fail; \
628
0
            } \
629
0
        } while (0)
630
0
#define SET_ITEM_INT(VAR) \
631
0
    SET_ITEM(#VAR, PyLong_FromLong(VAR))
632
0
#define FROM_STRING(STR) \
633
0
    ((STR != NULL) ? \
634
0
        PyUnicode_FromString(STR) \
635
0
        : Py_NewRef(Py_None))
636
0
#define SET_ITEM_STR(VAR) \
637
0
    SET_ITEM(#VAR, FROM_STRING(VAR))
638
639
0
    SET_ITEM_STR(Py_FileSystemDefaultEncoding);
640
0
    SET_ITEM_INT(Py_HasFileSystemDefaultEncoding);
641
0
    SET_ITEM_STR(Py_FileSystemDefaultEncodeErrors);
642
0
    SET_ITEM_INT(_Py_HasFileSystemDefaultEncodeErrors);
643
644
0
    SET_ITEM_INT(Py_UTF8Mode);
645
646
0
    return dict;
647
648
0
fail:
649
0
    Py_DECREF(dict);
650
0
    return NULL;
651
652
0
#undef FROM_STRING
653
0
#undef SET_ITEM
654
0
#undef SET_ITEM_INT
655
0
#undef SET_ITEM_STR
656
0
}
657
658
char*
659
Py_GETENV(const char *name)
660
444
{
661
444
    int use_environment = 1;
662
444
    PyThreadState *tstate = PyThreadState_GetUnchecked();
663
444
    if (tstate != NULL) {
664
37
        const PyConfig *config = &tstate->interp->config;
665
37
        use_environment = config->use_environment;
666
37
    }
667
668
444
    if (!use_environment) {
669
0
        return NULL;
670
0
    }
671
444
    return getenv(name);
672
444
}
673
674
/* --- PyStatus ----------------------------------------------- */
675
676
PyStatus PyStatus_Ok(void)
677
111
{ return _PyStatus_OK(); }
678
679
PyStatus PyStatus_Error(const char *err_msg)
680
0
{
681
0
    assert(err_msg != NULL);
682
0
    return (PyStatus){._type = _PyStatus_TYPE_ERROR,
683
0
                      .err_msg = err_msg};
684
0
}
685
686
PyStatus PyStatus_NoMemory(void)
687
0
{ return PyStatus_Error("memory allocation failed"); }
688
689
PyStatus PyStatus_Exit(int exitcode)
690
0
{ return _PyStatus_EXIT(exitcode); }
691
692
693
int PyStatus_IsError(PyStatus status)
694
0
{ return _PyStatus_IS_ERROR(status); }
695
696
int PyStatus_IsExit(PyStatus status)
697
0
{ return _PyStatus_IS_EXIT(status); }
698
699
int PyStatus_Exception(PyStatus status)
700
0
{ return _PyStatus_EXCEPTION(status); }
701
702
void
703
_PyErr_SetFromPyStatus(PyStatus status)
704
0
{
705
0
    if (!_PyStatus_IS_ERROR(status)) {
706
0
        PyErr_Format(PyExc_SystemError,
707
0
                     "_PyErr_SetFromPyStatus() status is not an error");
708
0
        return;
709
0
    }
710
711
0
    const char *err_msg = status.err_msg;
712
0
    if (err_msg == NULL || strlen(err_msg) == 0) {
713
0
        PyErr_Format(PyExc_SystemError,
714
0
                     "_PyErr_SetFromPyStatus() status has no error message");
715
0
        return;
716
0
    }
717
718
0
    if (strcmp(err_msg, _PyStatus_NO_MEMORY_ERRMSG) == 0) {
719
0
        PyErr_NoMemory();
720
0
        return;
721
0
    }
722
723
0
    const char *func = status.func;
724
0
    if (func) {
725
0
        PyErr_Format(PyExc_RuntimeError, "%s: %s", func, err_msg);
726
0
    }
727
0
    else {
728
0
        PyErr_Format(PyExc_RuntimeError, "%s", err_msg);
729
0
    }
730
0
}
731
732
733
/* --- PyWideStringList ------------------------------------------------ */
734
735
#ifndef NDEBUG
736
int
737
_PyWideStringList_CheckConsistency(const PyWideStringList *list)
738
{
739
    assert(list->length >= 0);
740
    if (list->length != 0) {
741
        assert(list->items != NULL);
742
    }
743
    for (Py_ssize_t i = 0; i < list->length; i++) {
744
        assert(list->items[i] != NULL);
745
    }
746
    return 1;
747
}
748
#endif   /* Py_DEBUG */
749
750
751
static void
752
_PyWideStringList_ClearEx(PyWideStringList *list,
753
                          bool use_default_allocator)
754
1.85k
{
755
1.85k
    assert(_PyWideStringList_CheckConsistency(list));
756
2.07k
    for (Py_ssize_t i=0; i < list->length; i++) {
757
222
        if (use_default_allocator) {
758
0
            _PyMem_DefaultRawFree(list->items[i]);
759
0
        }
760
222
        else {
761
222
            PyMem_RawFree(list->items[i]);
762
222
        }
763
222
    }
764
1.85k
    if (use_default_allocator) {
765
37
        _PyMem_DefaultRawFree(list->items);
766
37
    }
767
1.81k
    else {
768
1.81k
        PyMem_RawFree(list->items);
769
1.81k
    }
770
1.85k
    list->length = 0;
771
1.85k
    list->items = NULL;
772
1.85k
}
773
774
void
775
_PyWideStringList_Clear(PyWideStringList *list)
776
1.22k
{
777
1.22k
    _PyWideStringList_ClearEx(list, false);
778
1.22k
}
779
780
static int
781
_PyWideStringList_CopyEx(PyWideStringList *list,
782
                         const PyWideStringList *list2,
783
                         bool use_default_allocator)
784
629
{
785
629
    assert(_PyWideStringList_CheckConsistency(list));
786
629
    assert(_PyWideStringList_CheckConsistency(list2));
787
788
629
    if (list2->length == 0) {
789
518
        _PyWideStringList_ClearEx(list, use_default_allocator);
790
518
        return 0;
791
518
    }
792
793
111
    PyWideStringList copy = _PyWideStringList_INIT;
794
795
111
    size_t size = list2->length * sizeof(list2->items[0]);
796
111
    if (use_default_allocator) {
797
0
        copy.items = _PyMem_DefaultRawMalloc(size);
798
0
    }
799
111
    else {
800
111
        copy.items = PyMem_RawMalloc(size);
801
111
    }
802
111
    if (copy.items == NULL) {
803
0
        return -1;
804
0
    }
805
806
296
    for (Py_ssize_t i=0; i < list2->length; i++) {
807
185
        wchar_t *item;
808
185
        if (use_default_allocator) {
809
0
            item = _PyMem_DefaultRawWcsdup(list2->items[i]);
810
0
        }
811
185
        else {
812
185
            item = _PyMem_RawWcsdup(list2->items[i]);
813
185
        }
814
185
        if (item == NULL) {
815
0
            _PyWideStringList_ClearEx(&copy, use_default_allocator);
816
0
            return -1;
817
0
        }
818
185
        copy.items[i] = item;
819
185
        copy.length = i + 1;
820
185
    }
821
822
111
    _PyWideStringList_ClearEx(list, use_default_allocator);
823
111
    *list = copy;
824
111
    return 0;
825
111
}
826
827
int
828
_PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2)
829
592
{
830
592
    return _PyWideStringList_CopyEx(list, list2, false);
831
592
}
832
833
PyStatus
834
PyWideStringList_Insert(PyWideStringList *list,
835
                        Py_ssize_t index, const wchar_t *item)
836
185
{
837
185
    Py_ssize_t len = list->length;
838
185
    if (len == PY_SSIZE_T_MAX) {
839
        /* length+1 would overflow */
840
0
        return _PyStatus_NO_MEMORY();
841
0
    }
842
185
    if (index < 0) {
843
0
        return _PyStatus_ERR("PyWideStringList_Insert index must be >= 0");
844
0
    }
845
185
    if (index > len) {
846
0
        index = len;
847
0
    }
848
849
185
    wchar_t *item2 = _PyMem_RawWcsdup(item);
850
185
    if (item2 == NULL) {
851
0
        return _PyStatus_NO_MEMORY();
852
0
    }
853
854
185
    size_t size = (len + 1) * sizeof(list->items[0]);
855
185
    wchar_t **items2 = (wchar_t **)PyMem_RawRealloc(list->items, size);
856
185
    if (items2 == NULL) {
857
0
        PyMem_RawFree(item2);
858
0
        return _PyStatus_NO_MEMORY();
859
0
    }
860
861
185
    if (index < len) {
862
0
        memmove(&items2[index + 1],
863
0
                &items2[index],
864
0
                (len - index) * sizeof(items2[0]));
865
0
    }
866
867
185
    items2[index] = item2;
868
185
    list->items = items2;
869
185
    list->length++;
870
185
    return _PyStatus_OK();
871
185
}
872
873
874
PyStatus
875
PyWideStringList_Append(PyWideStringList *list, const wchar_t *item)
876
185
{
877
185
    return PyWideStringList_Insert(list, list->length, item);
878
185
}
879
880
881
PyStatus
882
_PyWideStringList_Extend(PyWideStringList *list, const PyWideStringList *list2)
883
74
{
884
74
    for (Py_ssize_t i = 0; i < list2->length; i++) {
885
0
        PyStatus status = PyWideStringList_Append(list, list2->items[i]);
886
0
        if (_PyStatus_EXCEPTION(status)) {
887
0
            return status;
888
0
        }
889
0
    }
890
74
    return _PyStatus_OK();
891
74
}
892
893
894
static int
895
_PyWideStringList_Find(PyWideStringList *list, const wchar_t *item)
896
0
{
897
0
    for (Py_ssize_t i = 0; i < list->length; i++) {
898
0
        if (wcscmp(list->items[i], item) == 0) {
899
0
            return 1;
900
0
        }
901
0
    }
902
0
    return 0;
903
0
}
904
905
906
PyObject*
907
_PyWideStringList_AsList(const PyWideStringList *list)
908
148
{
909
148
    assert(_PyWideStringList_CheckConsistency(list));
910
911
148
    PyObject *pylist = PyList_New(list->length);
912
148
    if (pylist == NULL) {
913
0
        return NULL;
914
0
    }
915
916
296
    for (Py_ssize_t i = 0; i < list->length; i++) {
917
148
        PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
918
148
        if (item == NULL) {
919
0
            Py_DECREF(pylist);
920
0
            return NULL;
921
0
        }
922
148
        PyList_SET_ITEM(pylist, i, item);
923
148
    }
924
148
    return pylist;
925
148
}
926
927
928
static PyObject*
929
_PyWideStringList_AsTuple(const PyWideStringList *list)
930
148
{
931
148
    assert(_PyWideStringList_CheckConsistency(list));
932
933
148
    PyObject *tuple = PyTuple_New(list->length);
934
148
    if (tuple == NULL) {
935
0
        return NULL;
936
0
    }
937
938
185
    for (Py_ssize_t i = 0; i < list->length; i++) {
939
37
        PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
940
37
        if (item == NULL) {
941
0
            Py_DECREF(tuple);
942
0
            return NULL;
943
0
        }
944
37
        PyTuple_SET_ITEM(tuple, i, item);
945
37
    }
946
148
    return tuple;
947
148
}
948
949
950
/* --- Py_GetArgcArgv() ------------------------------------------- */
951
952
void
953
_Py_ClearArgcArgv(void)
954
0
{
955
0
    _PyWideStringList_ClearEx(&_PyRuntime.orig_argv, true);
956
0
}
957
958
959
static int
960
_Py_SetArgcArgv(Py_ssize_t argc, wchar_t * const *argv)
961
37
{
962
37
    const PyWideStringList argv_list = {.length = argc, .items = (wchar_t **)argv};
963
964
    // XXX _PyRuntime.orig_argv only gets cleared by Py_Main(),
965
    // so it currently leaks for embedders.
966
37
    return _PyWideStringList_CopyEx(&_PyRuntime.orig_argv, &argv_list, true);
967
37
}
968
969
970
// _PyConfig_Write() calls _Py_SetArgcArgv() with PyConfig.orig_argv.
971
void
972
Py_GetArgcArgv(int *argc, wchar_t ***argv)
973
0
{
974
0
    *argc = (int)_PyRuntime.orig_argv.length;
975
0
    *argv = _PyRuntime.orig_argv.items;
976
0
}
977
978
979
/* --- PyConfig ---------------------------------------------- */
980
981
37
#define MAX_HASH_SEED 4294967295UL
982
983
984
#ifndef NDEBUG
985
static int
986
config_check_consistency(const PyConfig *config)
987
{
988
    /* Check config consistency */
989
    assert(config->isolated >= 0);
990
    assert(config->use_environment >= 0);
991
    assert(config->dev_mode >= 0);
992
    assert(config->install_signal_handlers >= 0);
993
    assert(config->use_hash_seed >= 0);
994
    assert(config->hash_seed <= MAX_HASH_SEED);
995
    assert(config->faulthandler >= 0);
996
    assert(config->tracemalloc >= 0);
997
    assert(config->import_time >= 0);
998
    assert(config->code_debug_ranges >= 0);
999
    assert(config->show_ref_count >= 0);
1000
    assert(config->dump_refs >= 0);
1001
    assert(config->malloc_stats >= 0);
1002
    assert(config->pymalloc_hugepages >= 0);
1003
    assert(config->site_import >= 0);
1004
    assert(config->bytes_warning >= 0);
1005
    assert(config->warn_default_encoding >= 0);
1006
    assert(config->inspect >= 0);
1007
    assert(config->interactive >= 0);
1008
    assert(config->optimization_level >= 0);
1009
    assert(config->parser_debug >= 0);
1010
    assert(config->write_bytecode >= 0);
1011
    assert(config->verbose >= 0);
1012
    assert(config->quiet >= 0);
1013
    assert(config->user_site_directory >= 0);
1014
    assert(config->parse_argv >= 0);
1015
    assert(config->configure_c_stdio >= 0);
1016
    assert(config->buffered_stdio >= 0);
1017
    assert(_PyWideStringList_CheckConsistency(&config->orig_argv));
1018
    assert(_PyWideStringList_CheckConsistency(&config->argv));
1019
    /* sys.argv must be non-empty: empty argv is replaced with [''] */
1020
    assert(config->argv.length >= 1);
1021
    assert(_PyWideStringList_CheckConsistency(&config->xoptions));
1022
    assert(_PyWideStringList_CheckConsistency(&config->warnoptions));
1023
    assert(_PyWideStringList_CheckConsistency(&config->module_search_paths));
1024
    assert(config->module_search_paths_set >= 0);
1025
    assert(config->filesystem_encoding != NULL);
1026
    assert(config->filesystem_errors != NULL);
1027
#ifdef MS_WINDOWS
1028
    /* stdio_encoding can be NULL in the legacy Windows stdio mode. */
1029
    assert(config->stdio_encoding != NULL || config->legacy_windows_stdio);
1030
    assert(config->legacy_windows_stdio >= 0);
1031
#else
1032
    assert(config->stdio_encoding != NULL);
1033
#endif
1034
    assert(config->stdio_errors != NULL);
1035
    /* -c and -m options are exclusive */
1036
    assert(!(config->run_command != NULL && config->run_module != NULL));
1037
    assert(config->check_hash_pycs_mode != NULL);
1038
    assert(config->_install_importlib >= 0);
1039
    assert(config->pathconfig_warnings >= 0);
1040
    assert(config->_is_python_build >= 0);
1041
    assert(config->safe_path >= 0);
1042
    assert(config->int_max_str_digits >= 0);
1043
    // cpu_count can be -1 if the user doesn't override it.
1044
    assert(config->cpu_count != 0);
1045
    // lazy_imports can be -1 (default) or 1 (on). 0 is rejected later
1046
    // for embedders with an error message.
1047
    assert(config->lazy_imports >= -1 && config->lazy_imports <= 1);
1048
    // config->use_frozen_modules is initialized later
1049
    // by _PyConfig_InitImportConfig().
1050
    assert(config->thread_inherit_context >= 0);
1051
    assert(config->context_aware_warnings >= 0);
1052
#ifdef __APPLE__
1053
    assert(config->use_system_logger >= 0);
1054
#endif
1055
#ifdef Py_STATS
1056
    assert(config->_pystats >= 0);
1057
#endif
1058
    return 1;
1059
}
1060
#endif
1061
1062
1063
/* Free memory allocated in config, but don't clear all attributes */
1064
void
1065
PyConfig_Clear(PyConfig *config)
1066
148
{
1067
148
#define CLEAR(ATTR) \
1068
3.10k
    do { \
1069
3.10k
        PyMem_RawFree(ATTR); \
1070
3.10k
        ATTR = NULL; \
1071
3.10k
    } while (0)
1072
1073
148
    CLEAR(config->pycache_prefix);
1074
148
    CLEAR(config->pythonpath_env);
1075
148
    CLEAR(config->home);
1076
148
    CLEAR(config->program_name);
1077
1078
148
    _PyWideStringList_Clear(&config->argv);
1079
148
    _PyWideStringList_Clear(&config->warnoptions);
1080
148
    _PyWideStringList_Clear(&config->xoptions);
1081
148
    _PyWideStringList_Clear(&config->module_search_paths);
1082
148
    config->module_search_paths_set = 0;
1083
148
    CLEAR(config->stdlib_dir);
1084
1085
148
    CLEAR(config->executable);
1086
148
    CLEAR(config->base_executable);
1087
148
    CLEAR(config->prefix);
1088
148
    CLEAR(config->base_prefix);
1089
148
    CLEAR(config->exec_prefix);
1090
148
    CLEAR(config->base_exec_prefix);
1091
148
    CLEAR(config->platlibdir);
1092
148
    CLEAR(config->sys_path_0);
1093
1094
148
    CLEAR(config->filesystem_encoding);
1095
148
    CLEAR(config->filesystem_errors);
1096
148
    CLEAR(config->stdio_encoding);
1097
148
    CLEAR(config->stdio_errors);
1098
148
    CLEAR(config->run_command);
1099
148
    CLEAR(config->run_module);
1100
148
    CLEAR(config->run_filename);
1101
148
    CLEAR(config->check_hash_pycs_mode);
1102
#ifdef Py_DEBUG
1103
    CLEAR(config->run_presite);
1104
#endif
1105
1106
148
    _PyWideStringList_Clear(&config->orig_argv);
1107
148
#undef CLEAR
1108
148
}
1109
1110
1111
void
1112
_PyConfig_InitCompatConfig(PyConfig *config)
1113
111
{
1114
111
    memset(config, 0, sizeof(*config));
1115
1116
111
    config->_config_init = (int)_PyConfig_INIT_COMPAT;
1117
111
    config->import_time = -1;
1118
111
    config->isolated = -1;
1119
111
    config->use_environment = -1;
1120
111
    config->dev_mode = -1;
1121
111
    config->install_signal_handlers = 1;
1122
111
    config->use_hash_seed = -1;
1123
111
    config->faulthandler = -1;
1124
111
    config->tracemalloc = -1;
1125
111
    config->perf_profiling = -1;
1126
111
    config->remote_debug = -1;
1127
111
    config->module_search_paths_set = 0;
1128
111
    config->parse_argv = 0;
1129
111
    config->site_import = -1;
1130
111
    config->bytes_warning = -1;
1131
111
    config->warn_default_encoding = 0;
1132
111
    config->inspect = -1;
1133
111
    config->interactive = -1;
1134
111
    config->optimization_level = -1;
1135
111
    config->parser_debug= -1;
1136
111
    config->write_bytecode = -1;
1137
111
    config->verbose = -1;
1138
111
    config->quiet = -1;
1139
111
    config->user_site_directory = -1;
1140
111
    config->configure_c_stdio = 0;
1141
111
    config->buffered_stdio = -1;
1142
111
    config->_install_importlib = 1;
1143
111
    config->check_hash_pycs_mode = NULL;
1144
111
    config->pathconfig_warnings = -1;
1145
111
    config->_init_main = 1;
1146
#ifdef MS_WINDOWS
1147
    config->legacy_windows_stdio = -1;
1148
#endif
1149
#ifdef Py_DEBUG
1150
    config->use_frozen_modules = 0;
1151
#else
1152
111
    config->use_frozen_modules = 1;
1153
111
#endif
1154
111
    config->safe_path = 0;
1155
111
    config->int_max_str_digits = -1;
1156
111
    config->_is_python_build = 0;
1157
111
    config->code_debug_ranges = 1;
1158
111
    config->cpu_count = -1;
1159
111
    config->lazy_imports = -1;
1160
#ifdef Py_GIL_DISABLED
1161
    config->thread_inherit_context = 1;
1162
    config->context_aware_warnings = 1;
1163
#else
1164
111
    config->thread_inherit_context = 0;
1165
111
    config->context_aware_warnings = 0;
1166
111
#endif
1167
#ifdef __APPLE__
1168
    config->use_system_logger = USE_SYSTEM_LOGGER_DEFAULT;
1169
#endif
1170
#ifdef Py_GIL_DISABLED
1171
    config->enable_gil = _PyConfig_GIL_DEFAULT;
1172
    config->tlbc_enabled = 1;
1173
#endif
1174
111
}
1175
1176
1177
static void
1178
config_init_defaults(PyConfig *config)
1179
74
{
1180
74
    _PyConfig_InitCompatConfig(config);
1181
1182
74
    config->isolated = 0;
1183
74
    config->use_environment = 1;
1184
74
    config->site_import = 1;
1185
74
    config->bytes_warning = 0;
1186
74
    config->inspect = 0;
1187
74
    config->interactive = 0;
1188
74
    config->optimization_level = 0;
1189
74
    config->parser_debug= 0;
1190
74
    config->write_bytecode = 1;
1191
74
    config->verbose = 0;
1192
74
    config->quiet = 0;
1193
74
    config->user_site_directory = 1;
1194
74
    config->buffered_stdio = 1;
1195
74
    config->pathconfig_warnings = 1;
1196
#ifdef MS_WINDOWS
1197
    config->legacy_windows_stdio = 0;
1198
#endif
1199
#ifdef Py_GIL_DISABLED
1200
    config->thread_inherit_context = 1;
1201
    config->context_aware_warnings = 1;
1202
#else
1203
74
    config->thread_inherit_context = 0;
1204
74
    config->context_aware_warnings = 0;
1205
74
#endif
1206
#ifdef __APPLE__
1207
    config->use_system_logger = USE_SYSTEM_LOGGER_DEFAULT;
1208
#endif
1209
74
}
1210
1211
1212
void
1213
PyConfig_InitPythonConfig(PyConfig *config)
1214
74
{
1215
74
    config_init_defaults(config);
1216
1217
74
    config->_config_init = (int)_PyConfig_INIT_PYTHON;
1218
74
    config->configure_c_stdio = 1;
1219
74
    config->parse_argv = 1;
1220
74
}
1221
1222
1223
void
1224
PyConfig_InitIsolatedConfig(PyConfig *config)
1225
0
{
1226
0
    config_init_defaults(config);
1227
1228
0
    config->_config_init = (int)_PyConfig_INIT_ISOLATED;
1229
0
    config->isolated = 1;
1230
0
    config->use_environment = 0;
1231
0
    config->user_site_directory = 0;
1232
0
    config->dev_mode = 0;
1233
0
    config->install_signal_handlers = 0;
1234
0
    config->use_hash_seed = 0;
1235
0
    config->tracemalloc = 0;
1236
0
    config->perf_profiling = 0;
1237
0
    config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS;
1238
0
    config->safe_path = 1;
1239
0
    config->pathconfig_warnings = 0;
1240
#ifdef Py_GIL_DISABLED
1241
    config->thread_inherit_context = 1;
1242
#else
1243
0
    config->thread_inherit_context = 0;
1244
0
#endif
1245
#ifdef MS_WINDOWS
1246
    config->legacy_windows_stdio = 0;
1247
#endif
1248
#ifdef __APPLE__
1249
    config->use_system_logger = USE_SYSTEM_LOGGER_DEFAULT;
1250
#endif
1251
0
}
1252
1253
1254
/* Copy str into *config_str (duplicate the string) */
1255
PyStatus
1256
PyConfig_SetString(PyConfig *config, wchar_t **config_str, const wchar_t *str)
1257
2.62k
{
1258
2.62k
    PyStatus status = _Py_PreInitializeFromConfig(config, NULL);
1259
2.62k
    if (_PyStatus_EXCEPTION(status)) {
1260
0
        return status;
1261
0
    }
1262
1263
2.62k
    wchar_t *str2;
1264
2.62k
    if (str != NULL) {
1265
925
        str2 = _PyMem_RawWcsdup(str);
1266
925
        if (str2 == NULL) {
1267
0
            return _PyStatus_NO_MEMORY();
1268
0
        }
1269
925
    }
1270
1.70k
    else {
1271
1.70k
        str2 = NULL;
1272
1.70k
    }
1273
2.62k
    PyMem_RawFree(*config_str);
1274
2.62k
    *config_str = str2;
1275
2.62k
    return _PyStatus_OK();
1276
2.62k
}
1277
1278
1279
static PyStatus
1280
config_set_bytes_string(PyConfig *config, wchar_t **config_str,
1281
                        const char *str, const char *decode_err_msg)
1282
0
{
1283
0
    PyStatus status = _Py_PreInitializeFromConfig(config, NULL);
1284
0
    if (_PyStatus_EXCEPTION(status)) {
1285
0
        return status;
1286
0
    }
1287
1288
0
    wchar_t *str2;
1289
0
    if (str != NULL) {
1290
0
        size_t len;
1291
0
        str2 = Py_DecodeLocale(str, &len);
1292
0
        if (str2 == NULL) {
1293
0
            if (len == (size_t)-2) {
1294
0
                return _PyStatus_ERR(decode_err_msg);
1295
0
            }
1296
0
            else {
1297
0
                return  _PyStatus_NO_MEMORY();
1298
0
            }
1299
0
        }
1300
0
    }
1301
0
    else {
1302
0
        str2 = NULL;
1303
0
    }
1304
0
    PyMem_RawFree(*config_str);
1305
0
    *config_str = str2;
1306
0
    return _PyStatus_OK();
1307
0
}
1308
1309
1310
#define CONFIG_SET_BYTES_STR(config, config_str, str, NAME) \
1311
0
    config_set_bytes_string(config, config_str, str, "cannot decode " NAME)
1312
1313
1314
/* Decode str using Py_DecodeLocale() and set the result into *config_str.
1315
   Pre-initialize Python if needed to ensure that encodings are properly
1316
   configured. */
1317
PyStatus
1318
PyConfig_SetBytesString(PyConfig *config, wchar_t **config_str,
1319
                        const char *str)
1320
0
{
1321
0
    return CONFIG_SET_BYTES_STR(config, config_str, str, "string");
1322
0
}
1323
1324
1325
static inline void*
1326
config_get_spec_member(const PyConfig *config, const PyConfigSpec *spec)
1327
13.3k
{
1328
13.3k
    return (char *)config + spec->offset;
1329
13.3k
}
1330
1331
1332
static inline void*
1333
preconfig_get_spec_member(const PyPreConfig *preconfig, const PyConfigSpec *spec)
1334
0
{
1335
0
    return (char *)preconfig + spec->offset;
1336
0
}
1337
1338
1339
PyStatus
1340
_PyConfig_Copy(PyConfig *config, const PyConfig *config2)
1341
74
{
1342
74
    PyConfig_Clear(config);
1343
1344
74
    PyStatus status;
1345
74
    const PyConfigSpec *spec = PYCONFIG_SPEC;
1346
5.40k
    for (; spec->name != NULL; spec++) {
1347
5.32k
        void *member = config_get_spec_member(config, spec);
1348
5.32k
        const void *member2 = config_get_spec_member((PyConfig*)config2, spec);
1349
5.32k
        switch (spec->type) {
1350
370
        case PyConfig_MEMBER_INT:
1351
962
        case PyConfig_MEMBER_UINT:
1352
3.25k
        case PyConfig_MEMBER_BOOL:
1353
3.25k
        {
1354
3.25k
            *(int*)member = *(int*)member2;
1355
3.25k
            break;
1356
962
        }
1357
74
        case PyConfig_MEMBER_ULONG:
1358
74
        {
1359
74
            *(unsigned long*)member = *(unsigned long*)member2;
1360
74
            break;
1361
962
        }
1362
444
        case PyConfig_MEMBER_WSTR:
1363
1.62k
        case PyConfig_MEMBER_WSTR_OPT:
1364
1.62k
        {
1365
1.62k
            const wchar_t *str = *(const wchar_t**)member2;
1366
1.62k
            status = PyConfig_SetString(config, (wchar_t**)member, str);
1367
1.62k
            if (_PyStatus_EXCEPTION(status)) {
1368
0
                return status;
1369
0
            }
1370
1.62k
            break;
1371
1.62k
        }
1372
1.62k
        case PyConfig_MEMBER_WSTR_LIST:
1373
370
        {
1374
370
            if (_PyWideStringList_Copy((PyWideStringList*)member,
1375
370
                                       (const PyWideStringList*)member2) < 0) {
1376
0
                return _PyStatus_NO_MEMORY();
1377
0
            }
1378
370
            break;
1379
370
        }
1380
370
        default:
1381
0
            Py_UNREACHABLE();
1382
5.32k
        }
1383
5.32k
    }
1384
74
    return _PyStatus_OK();
1385
74
}
1386
1387
1388
PyObject *
1389
_PyConfig_AsDict(const PyConfig *config)
1390
37
{
1391
37
    PyObject *dict = PyDict_New();
1392
37
    if (dict == NULL) {
1393
0
        return NULL;
1394
0
    }
1395
1396
37
    const PyConfigSpec *spec = PYCONFIG_SPEC;
1397
2.70k
    for (; spec->name != NULL; spec++) {
1398
2.66k
        PyObject *obj = config_get(config, spec, 0);
1399
2.66k
        if (obj == NULL) {
1400
0
            Py_DECREF(dict);
1401
0
            return NULL;
1402
0
        }
1403
1404
2.66k
        int res = PyDict_SetItemString(dict, spec->name, obj);
1405
2.66k
        Py_DECREF(obj);
1406
2.66k
        if (res < 0) {
1407
0
            Py_DECREF(dict);
1408
0
            return NULL;
1409
0
        }
1410
2.66k
    }
1411
37
    return dict;
1412
37
}
1413
1414
1415
static void
1416
config_dict_invalid_value(const char *name)
1417
0
{
1418
0
    PyErr_Format(PyExc_ValueError, "invalid config value: %s", name);
1419
0
}
1420
1421
1422
static int
1423
config_dict_get_int(PyObject *dict, const char *name, int *result)
1424
1.62k
{
1425
1.62k
    PyObject *item = config_dict_get(dict, name);
1426
1.62k
    if (item == NULL) {
1427
0
        return -1;
1428
0
    }
1429
1.62k
    int value = PyLong_AsInt(item);
1430
1.62k
    Py_DECREF(item);
1431
1.62k
    if (value == -1 && PyErr_Occurred()) {
1432
0
        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
1433
0
            config_dict_invalid_type(name);
1434
0
        }
1435
0
        else if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
1436
0
            config_dict_invalid_value(name);
1437
0
        }
1438
0
        return -1;
1439
0
    }
1440
1.62k
    *result = value;
1441
1.62k
    return 0;
1442
1.62k
}
1443
1444
1445
static int
1446
config_dict_get_ulong(PyObject *dict, const char *name, unsigned long *result)
1447
37
{
1448
37
    PyObject *item = config_dict_get(dict, name);
1449
37
    if (item == NULL) {
1450
0
        return -1;
1451
0
    }
1452
37
    unsigned long value = PyLong_AsUnsignedLong(item);
1453
37
    Py_DECREF(item);
1454
37
    if (value == (unsigned long)-1 && PyErr_Occurred()) {
1455
0
        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
1456
0
            config_dict_invalid_type(name);
1457
0
        }
1458
0
        else if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
1459
0
            config_dict_invalid_value(name);
1460
0
        }
1461
0
        return -1;
1462
0
    }
1463
37
    *result = value;
1464
37
    return 0;
1465
37
}
1466
1467
1468
static int
1469
config_dict_get_wstr(PyObject *dict, const char *name, PyConfig *config,
1470
                     wchar_t **result)
1471
814
{
1472
814
    PyObject *item = config_dict_get(dict, name);
1473
814
    if (item == NULL) {
1474
0
        return -1;
1475
0
    }
1476
1477
814
    PyStatus status;
1478
814
    if (item == Py_None) {
1479
259
        status = PyConfig_SetString(config, result, NULL);
1480
259
    }
1481
555
    else if (!PyUnicode_Check(item)) {
1482
0
        config_dict_invalid_type(name);
1483
0
        goto error;
1484
0
    }
1485
555
    else {
1486
555
        wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL);
1487
555
        if (wstr == NULL) {
1488
0
            goto error;
1489
0
        }
1490
555
        status = PyConfig_SetString(config, result, wstr);
1491
555
        PyMem_Free(wstr);
1492
555
    }
1493
814
    if (_PyStatus_EXCEPTION(status)) {
1494
0
        PyErr_NoMemory();
1495
0
        goto error;
1496
0
    }
1497
814
    Py_DECREF(item);
1498
814
    return 0;
1499
1500
0
error:
1501
0
    Py_DECREF(item);
1502
0
    return -1;
1503
814
}
1504
1505
1506
static int
1507
config_dict_get_wstrlist(PyObject *dict, const char *name, PyConfig *config,
1508
                         PyWideStringList *result)
1509
148
{
1510
148
    PyObject *list = config_dict_get(dict, name);
1511
148
    if (list == NULL) {
1512
0
        return -1;
1513
0
    }
1514
1515
148
    int is_list = PyList_CheckExact(list);
1516
148
    if (!is_list && !PyTuple_CheckExact(list)) {
1517
0
        Py_DECREF(list);
1518
0
        config_dict_invalid_type(name);
1519
0
        return -1;
1520
0
    }
1521
1522
148
    PyWideStringList wstrlist = _PyWideStringList_INIT;
1523
148
    Py_ssize_t len = is_list ? PyList_GET_SIZE(list) : PyTuple_GET_SIZE(list);
1524
296
    for (Py_ssize_t i=0; i < len; i++) {
1525
148
        PyObject *item = is_list ? PyList_GET_ITEM(list, i) : PyTuple_GET_ITEM(list, i);
1526
1527
148
        if (item == Py_None) {
1528
0
            config_dict_invalid_value(name);
1529
0
            goto error;
1530
0
        }
1531
148
        else if (!PyUnicode_Check(item)) {
1532
0
            config_dict_invalid_type(name);
1533
0
            goto error;
1534
0
        }
1535
148
        wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL);
1536
148
        if (wstr == NULL) {
1537
0
            goto error;
1538
0
        }
1539
148
        PyStatus status = PyWideStringList_Append(&wstrlist, wstr);
1540
148
        PyMem_Free(wstr);
1541
148
        if (_PyStatus_EXCEPTION(status)) {
1542
0
            PyErr_NoMemory();
1543
0
            goto error;
1544
0
        }
1545
148
    }
1546
1547
148
    if (_PyWideStringList_Copy(result, &wstrlist) < 0) {
1548
0
        PyErr_NoMemory();
1549
0
        goto error;
1550
0
    }
1551
148
    _PyWideStringList_Clear(&wstrlist);
1552
148
    Py_DECREF(list);
1553
148
    return 0;
1554
1555
0
error:
1556
0
    _PyWideStringList_Clear(&wstrlist);
1557
0
    Py_DECREF(list);
1558
0
    return -1;
1559
148
}
1560
1561
1562
static int
1563
config_dict_get_xoptions(PyObject *dict, const char *name, PyConfig *config,
1564
                         PyWideStringList *result)
1565
37
{
1566
37
    PyObject *xoptions = config_dict_get(dict, name);
1567
37
    if (xoptions == NULL) {
1568
0
        return -1;
1569
0
    }
1570
1571
37
    if (!PyDict_CheckExact(xoptions)) {
1572
0
        Py_DECREF(xoptions);
1573
0
        config_dict_invalid_type(name);
1574
0
        return -1;
1575
0
    }
1576
1577
37
    Py_ssize_t pos = 0;
1578
37
    PyObject *key, *value;
1579
37
    PyWideStringList wstrlist = _PyWideStringList_INIT;
1580
37
    while (PyDict_Next(xoptions, &pos, &key, &value)) {
1581
0
        PyObject *item;
1582
1583
0
        if (value != Py_True) {
1584
0
            item = PyUnicode_FromFormat("%S=%S", key, value);
1585
0
            if (item == NULL) {
1586
0
                goto error;
1587
0
            }
1588
0
        }
1589
0
        else {
1590
0
            item = Py_NewRef(key);
1591
0
        }
1592
1593
0
        wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL);
1594
0
        Py_DECREF(item);
1595
0
        if (wstr == NULL) {
1596
0
            goto error;
1597
0
        }
1598
1599
0
        PyStatus status = PyWideStringList_Append(&wstrlist, wstr);
1600
0
        PyMem_Free(wstr);
1601
0
        if (_PyStatus_EXCEPTION(status)) {
1602
0
            PyErr_NoMemory();
1603
0
            goto error;
1604
0
        }
1605
0
    }
1606
1607
37
    if (_PyWideStringList_Copy(result, &wstrlist) < 0) {
1608
0
        PyErr_NoMemory();
1609
0
        goto error;
1610
0
    }
1611
37
    _PyWideStringList_Clear(&wstrlist);
1612
37
    Py_DECREF(xoptions);
1613
37
    return 0;
1614
1615
0
error:
1616
0
    _PyWideStringList_Clear(&wstrlist);
1617
0
    Py_DECREF(xoptions);
1618
0
    return -1;
1619
37
}
1620
1621
1622
int
1623
_PyConfig_FromDict(PyConfig *config, PyObject *dict)
1624
37
{
1625
37
    if (!PyDict_Check(dict)) {
1626
0
        PyErr_SetString(PyExc_TypeError, "dict expected");
1627
0
        return -1;
1628
0
    }
1629
1630
37
    const PyConfigSpec *spec = PYCONFIG_SPEC;
1631
2.70k
    for (; spec->name != NULL; spec++) {
1632
2.66k
        char *member = (char *)config + spec->offset;
1633
2.66k
        switch (spec->type) {
1634
185
        case PyConfig_MEMBER_INT:
1635
481
        case PyConfig_MEMBER_UINT:
1636
1.62k
        case PyConfig_MEMBER_BOOL:
1637
1.62k
        {
1638
1.62k
            int value;
1639
1.62k
            if (config_dict_get_int(dict, spec->name, &value) < 0) {
1640
0
                return -1;
1641
0
            }
1642
1.62k
            if (spec->type == PyConfig_MEMBER_BOOL
1643
481
                || spec->type == PyConfig_MEMBER_UINT)
1644
1.44k
            {
1645
1.44k
                if (value < 0) {
1646
0
                    config_dict_invalid_value(spec->name);
1647
0
                    return -1;
1648
0
                }
1649
1.44k
            }
1650
1.62k
            *(int*)member = value;
1651
1.62k
            break;
1652
1.62k
        }
1653
37
        case PyConfig_MEMBER_ULONG:
1654
37
        {
1655
37
            if (config_dict_get_ulong(dict, spec->name,
1656
37
                                      (unsigned long*)member) < 0) {
1657
0
                return -1;
1658
0
            }
1659
37
            break;
1660
37
        }
1661
222
        case PyConfig_MEMBER_WSTR:
1662
222
        {
1663
222
            wchar_t **wstr = (wchar_t**)member;
1664
222
            if (config_dict_get_wstr(dict, spec->name, config, wstr) < 0) {
1665
0
                return -1;
1666
0
            }
1667
222
            if (*wstr == NULL) {
1668
0
                config_dict_invalid_value(spec->name);
1669
0
                return -1;
1670
0
            }
1671
222
            break;
1672
222
        }
1673
592
        case PyConfig_MEMBER_WSTR_OPT:
1674
592
        {
1675
592
            wchar_t **wstr = (wchar_t**)member;
1676
592
            if (config_dict_get_wstr(dict, spec->name, config, wstr) < 0) {
1677
0
                return -1;
1678
0
            }
1679
592
            break;
1680
592
        }
1681
592
        case PyConfig_MEMBER_WSTR_LIST:
1682
185
        {
1683
185
            if (strcmp(spec->name, "xoptions") == 0) {
1684
37
                if (config_dict_get_xoptions(dict, spec->name, config,
1685
37
                                             (PyWideStringList*)member) < 0) {
1686
0
                    return -1;
1687
0
                }
1688
37
            }
1689
148
            else {
1690
148
                if (config_dict_get_wstrlist(dict, spec->name, config,
1691
148
                                             (PyWideStringList*)member) < 0) {
1692
0
                    return -1;
1693
0
                }
1694
148
            }
1695
185
            break;
1696
185
        }
1697
185
        default:
1698
0
            Py_UNREACHABLE();
1699
2.66k
        }
1700
2.66k
    }
1701
1702
37
    if (!(config->_config_init == _PyConfig_INIT_COMPAT
1703
0
          || config->_config_init == _PyConfig_INIT_PYTHON
1704
0
          || config->_config_init == _PyConfig_INIT_ISOLATED))
1705
0
    {
1706
0
        config_dict_invalid_value("_config_init");
1707
0
        return -1;
1708
0
    }
1709
1710
37
    if (config->hash_seed > MAX_HASH_SEED) {
1711
0
        config_dict_invalid_value("hash_seed");
1712
0
        return -1;
1713
0
    }
1714
37
    return 0;
1715
37
}
1716
1717
1718
static const char*
1719
config_get_env(const PyConfig *config, const char *name)
1720
740
{
1721
740
    return _Py_GetEnv(config->use_environment, name);
1722
740
}
1723
1724
1725
/* Get a copy of the environment variable as wchar_t*.
1726
   Return 0 on success, but *dest can be NULL.
1727
   Return -1 on memory allocation failure. Return -2 on decoding error. */
1728
static PyStatus
1729
config_get_env_dup(PyConfig *config,
1730
                   wchar_t **dest,
1731
                   wchar_t *wname, char *name,
1732
                   const char *decode_err_msg)
1733
185
{
1734
185
    assert(*dest == NULL);
1735
185
    assert(config->use_environment >= 0);
1736
1737
185
    if (!config->use_environment) {
1738
0
        *dest = NULL;
1739
0
        return _PyStatus_OK();
1740
0
    }
1741
1742
#ifdef MS_WINDOWS
1743
    const wchar_t *var = _wgetenv(wname);
1744
    if (!var || var[0] == '\0') {
1745
        *dest = NULL;
1746
        return _PyStatus_OK();
1747
    }
1748
1749
    return PyConfig_SetString(config, dest, var);
1750
#else
1751
185
    const char *var = getenv(name);
1752
185
    if (!var || var[0] == '\0') {
1753
185
        *dest = NULL;
1754
185
        return _PyStatus_OK();
1755
185
    }
1756
1757
0
    return config_set_bytes_string(config, dest, var, decode_err_msg);
1758
185
#endif
1759
185
}
1760
1761
1762
#define CONFIG_GET_ENV_DUP(CONFIG, DEST, WNAME, NAME) \
1763
185
    config_get_env_dup(CONFIG, DEST, WNAME, NAME, "cannot decode " NAME)
1764
1765
1766
static void
1767
config_read_preconfig(PyConfig *config)
1768
37
{
1769
37
#define COPY_FLAG(ATTR) \
1770
111
        if (config->ATTR == -1) { \
1771
111
            config->ATTR = preconfig->ATTR; \
1772
111
        }
1773
1774
37
    const PyPreConfig *preconfig = &_PyRuntime.preconfig;
1775
37
    COPY_FLAG(isolated);
1776
37
    COPY_FLAG(use_environment);
1777
37
    COPY_FLAG(dev_mode);
1778
1779
37
#undef COPY_FLAG
1780
37
}
1781
1782
1783
static const wchar_t*
1784
config_get_xoption(const PyConfig *config, wchar_t *name)
1785
666
{
1786
666
    return _Py_get_xoption(&config->xoptions, name);
1787
666
}
1788
1789
static const wchar_t*
1790
config_get_xoption_value(const PyConfig *config, wchar_t *name)
1791
185
{
1792
185
    const wchar_t *xoption = config_get_xoption(config, name);
1793
185
    if (xoption == NULL) {
1794
185
        return NULL;
1795
185
    }
1796
0
    const wchar_t *sep = wcschr(xoption, L'=');
1797
0
    return sep ? sep + 1 : L"";
1798
185
}
1799
1800
1801
static PyStatus
1802
config_init_hash_seed(PyConfig *config)
1803
37
{
1804
37
    static_assert(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc),
1805
37
                  "_Py_HashSecret_t has wrong size");
1806
1807
37
    const char *seed_text = config_get_env(config, "PYTHONHASHSEED");
1808
1809
    /* Convert a text seed to a numeric one */
1810
37
    if (seed_text && strcmp(seed_text, "random") != 0) {
1811
0
        const char *endptr = seed_text;
1812
0
        unsigned long seed;
1813
0
        errno = 0;
1814
0
        seed = strtoul(seed_text, (char **)&endptr, 10);
1815
0
        if (*endptr != '\0'
1816
0
            || seed > MAX_HASH_SEED
1817
0
            || (errno == ERANGE && seed == ULONG_MAX))
1818
0
        {
1819
0
            return _PyStatus_ERR("PYTHONHASHSEED must be \"random\" "
1820
0
                                "or an integer in range [0; 4294967295]");
1821
0
        }
1822
        /* Use a specific hash */
1823
0
        config->use_hash_seed = 1;
1824
0
        config->hash_seed = seed;
1825
0
    }
1826
37
    else {
1827
        /* Use a random hash */
1828
37
        config->use_hash_seed = 0;
1829
37
        config->hash_seed = 0;
1830
37
    }
1831
37
    return _PyStatus_OK();
1832
37
}
1833
1834
1835
static int
1836
config_wstr_to_int(const wchar_t *wstr, int *result)
1837
0
{
1838
0
    const wchar_t *endptr = wstr;
1839
0
    errno = 0;
1840
0
    long value = wcstol(wstr, (wchar_t **)&endptr, 10);
1841
0
    if (*endptr != '\0' || errno == ERANGE) {
1842
0
        return -1;
1843
0
    }
1844
0
    if (value < INT_MIN || value > INT_MAX) {
1845
0
        return -1;
1846
0
    }
1847
1848
0
    *result = (int)value;
1849
0
    return 0;
1850
0
}
1851
1852
static PyStatus
1853
config_read_gil(PyConfig *config, size_t len, wchar_t first_char)
1854
0
{
1855
0
    if (len == 1 && first_char == L'0') {
1856
#ifdef Py_GIL_DISABLED
1857
        config->enable_gil = _PyConfig_GIL_DISABLE;
1858
#else
1859
0
        return _PyStatus_ERR("Disabling the GIL is not supported by this build");
1860
0
#endif
1861
0
    }
1862
0
    else if (len == 1 && first_char == L'1') {
1863
#ifdef Py_GIL_DISABLED
1864
        config->enable_gil = _PyConfig_GIL_ENABLE;
1865
#else
1866
0
        return _PyStatus_OK();
1867
0
#endif
1868
0
    }
1869
0
    else {
1870
0
        return _PyStatus_ERR("PYTHON_GIL / -X gil must be \"0\" or \"1\"");
1871
0
    }
1872
0
    return _PyStatus_OK();
1873
0
}
1874
1875
static PyStatus
1876
config_read_env_vars(PyConfig *config)
1877
37
{
1878
37
    PyStatus status;
1879
37
    int use_env = config->use_environment;
1880
1881
    /* Get environment variables */
1882
37
    _Py_get_env_flag(use_env, &config->parser_debug, "PYTHONDEBUG");
1883
37
    _Py_get_env_flag(use_env, &config->verbose, "PYTHONVERBOSE");
1884
37
    _Py_get_env_flag(use_env, &config->optimization_level, "PYTHONOPTIMIZE");
1885
37
    if (!config->inspect && _Py_GetEnv(use_env, "PYTHONINSPECT")) {
1886
0
        config->inspect = 1;
1887
0
    }
1888
1889
37
    int dont_write_bytecode = 0;
1890
37
    _Py_get_env_flag(use_env, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE");
1891
37
    if (dont_write_bytecode) {
1892
0
        config->write_bytecode = 0;
1893
0
    }
1894
1895
37
    int no_user_site_directory = 0;
1896
37
    _Py_get_env_flag(use_env, &no_user_site_directory, "PYTHONNOUSERSITE");
1897
37
    if (no_user_site_directory) {
1898
0
        config->user_site_directory = 0;
1899
0
    }
1900
1901
37
    int unbuffered_stdio = 0;
1902
37
    _Py_get_env_flag(use_env, &unbuffered_stdio, "PYTHONUNBUFFERED");
1903
37
    if (unbuffered_stdio) {
1904
0
        config->buffered_stdio = 0;
1905
0
    }
1906
1907
#ifdef MS_WINDOWS
1908
    _Py_get_env_flag(use_env, &config->legacy_windows_stdio,
1909
                     "PYTHONLEGACYWINDOWSSTDIO");
1910
#endif
1911
1912
37
    if (config_get_env(config, "PYTHONDUMPREFS")) {
1913
0
        config->dump_refs = 1;
1914
0
    }
1915
37
    if (config_get_env(config, "PYTHONMALLOCSTATS")) {
1916
0
        config->malloc_stats = 1;
1917
0
    }
1918
37
    {
1919
37
        const char *env = _Py_GetEnv(use_env, "PYTHON_PYMALLOC_HUGEPAGES");
1920
37
        if (env) {
1921
0
            int value;
1922
0
            if (_Py_str_to_int(env, &value) < 0 || value < 0) {
1923
                /* PYTHON_PYMALLOC_HUGEPAGES=text or negative
1924
                   behaves as PYTHON_PYMALLOC_HUGEPAGES=1 */
1925
0
                value = 1;
1926
0
            }
1927
0
            config->pymalloc_hugepages = (value > 0);
1928
0
        }
1929
37
    }
1930
1931
37
    if (config->dump_refs_file == NULL) {
1932
37
        status = CONFIG_GET_ENV_DUP(config, &config->dump_refs_file,
1933
37
                                    L"PYTHONDUMPREFSFILE", "PYTHONDUMPREFSFILE");
1934
37
        if (_PyStatus_EXCEPTION(status)) {
1935
0
            return status;
1936
0
        }
1937
37
    }
1938
1939
37
    if (config->pythonpath_env == NULL) {
1940
37
        status = CONFIG_GET_ENV_DUP(config, &config->pythonpath_env,
1941
37
                                    L"PYTHONPATH", "PYTHONPATH");
1942
37
        if (_PyStatus_EXCEPTION(status)) {
1943
0
            return status;
1944
0
        }
1945
37
    }
1946
1947
37
    if(config->platlibdir == NULL) {
1948
37
        status = CONFIG_GET_ENV_DUP(config, &config->platlibdir,
1949
37
                                    L"PYTHONPLATLIBDIR", "PYTHONPLATLIBDIR");
1950
37
        if (_PyStatus_EXCEPTION(status)) {
1951
0
            return status;
1952
0
        }
1953
37
    }
1954
1955
37
    if (config->use_hash_seed < 0) {
1956
37
        status = config_init_hash_seed(config);
1957
37
        if (_PyStatus_EXCEPTION(status)) {
1958
0
            return status;
1959
0
        }
1960
37
    }
1961
1962
37
    if (config_get_env(config, "PYTHONSAFEPATH")) {
1963
0
        config->safe_path = 1;
1964
0
    }
1965
1966
37
    const char *gil = config_get_env(config, "PYTHON_GIL");
1967
37
    if (gil != NULL) {
1968
0
        size_t len = strlen(gil);
1969
0
        status = config_read_gil(config, len, gil[0]);
1970
0
        if (_PyStatus_EXCEPTION(status)) {
1971
0
            return status;
1972
0
        }
1973
0
    }
1974
1975
37
    return _PyStatus_OK();
1976
37
}
1977
1978
static PyStatus
1979
config_init_cpu_count(PyConfig *config)
1980
37
{
1981
37
    const char *env = config_get_env(config, "PYTHON_CPU_COUNT");
1982
37
    if (env) {
1983
0
        int cpu_count = -1;
1984
0
        if (strcmp(env, "default") == 0) {
1985
0
            cpu_count = -1;
1986
0
        }
1987
0
        else if (_Py_str_to_int(env, &cpu_count) < 0 || cpu_count < 1) {
1988
0
            goto error;
1989
0
        }
1990
0
        config->cpu_count = cpu_count;
1991
0
    }
1992
1993
37
    const wchar_t *xoption = config_get_xoption(config, L"cpu_count");
1994
37
    if (xoption) {
1995
0
        int cpu_count = -1;
1996
0
        const wchar_t *sep = wcschr(xoption, L'=');
1997
0
        if (sep) {
1998
0
            if (wcscmp(sep + 1, L"default") == 0) {
1999
0
                cpu_count = -1;
2000
0
            }
2001
0
            else if (config_wstr_to_int(sep + 1, &cpu_count) < 0 || cpu_count < 1) {
2002
0
                goto error;
2003
0
            }
2004
0
        }
2005
0
        else {
2006
0
            goto error;
2007
0
        }
2008
0
        config->cpu_count = cpu_count;
2009
0
    }
2010
37
    return _PyStatus_OK();
2011
2012
0
error:
2013
0
    return _PyStatus_ERR("-X cpu_count=n option: n is missing or an invalid number, "
2014
37
                         "n must be greater than 0");
2015
37
}
2016
2017
static PyStatus
2018
config_init_thread_inherit_context(PyConfig *config)
2019
37
{
2020
37
    const char *env = config_get_env(config, "PYTHON_THREAD_INHERIT_CONTEXT");
2021
37
    if (env) {
2022
0
        int enabled;
2023
0
        if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
2024
0
            return _PyStatus_ERR(
2025
0
                "PYTHON_THREAD_INHERIT_CONTEXT=N: N is missing or invalid");
2026
0
        }
2027
0
        config->thread_inherit_context = enabled;
2028
0
    }
2029
2030
37
    const wchar_t *xoption = config_get_xoption(config, L"thread_inherit_context");
2031
37
    if (xoption) {
2032
0
        int enabled;
2033
0
        const wchar_t *sep = wcschr(xoption, L'=');
2034
0
        if (!sep || (config_wstr_to_int(sep + 1, &enabled) < 0) || (enabled < 0) || (enabled > 1)) {
2035
0
            return _PyStatus_ERR(
2036
0
                "-X thread_inherit_context=n: n is missing or invalid");
2037
0
        }
2038
0
        config->thread_inherit_context = enabled;
2039
0
    }
2040
37
    return _PyStatus_OK();
2041
37
}
2042
2043
static PyStatus
2044
config_init_context_aware_warnings(PyConfig *config)
2045
37
{
2046
37
    const char *env = config_get_env(config, "PYTHON_CONTEXT_AWARE_WARNINGS");
2047
37
    if (env) {
2048
0
        int enabled;
2049
0
        if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
2050
0
            return _PyStatus_ERR(
2051
0
                "PYTHON_CONTEXT_AWARE_WARNINGS=N: N is missing or invalid");
2052
0
        }
2053
0
        config->context_aware_warnings = enabled;
2054
0
    }
2055
2056
37
    const wchar_t *xoption = config_get_xoption(config, L"context_aware_warnings");
2057
37
    if (xoption) {
2058
0
        int enabled;
2059
0
        const wchar_t *sep = wcschr(xoption, L'=');
2060
0
        if (!sep || (config_wstr_to_int(sep + 1, &enabled) < 0) || (enabled < 0) || (enabled > 1)) {
2061
0
            return _PyStatus_ERR(
2062
0
                "-X context_aware_warnings=n: n is missing or invalid");
2063
0
        }
2064
0
        config->context_aware_warnings = enabled;
2065
0
    }
2066
37
    return _PyStatus_OK();
2067
37
}
2068
2069
static PyStatus
2070
config_init_tlbc(PyConfig *config)
2071
37
{
2072
#ifdef Py_GIL_DISABLED
2073
    const char *env = config_get_env(config, "PYTHON_TLBC");
2074
    if (env) {
2075
        int enabled;
2076
        if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
2077
            return _PyStatus_ERR(
2078
                "PYTHON_TLBC=N: N is missing or invalid");
2079
        }
2080
        config->tlbc_enabled = enabled;
2081
    }
2082
2083
    const wchar_t *xoption = config_get_xoption(config, L"tlbc");
2084
    if (xoption) {
2085
        int enabled;
2086
        const wchar_t *sep = wcschr(xoption, L'=');
2087
        if (!sep || (config_wstr_to_int(sep + 1, &enabled) < 0) || (enabled < 0) || (enabled > 1)) {
2088
            return _PyStatus_ERR(
2089
                "-X tlbc=n: n is missing or invalid");
2090
        }
2091
        config->tlbc_enabled = enabled;
2092
    }
2093
    return _PyStatus_OK();
2094
#else
2095
37
    return _PyStatus_OK();
2096
37
#endif
2097
37
}
2098
2099
static PyStatus
2100
config_init_perf_profiling(PyConfig *config)
2101
37
{
2102
37
    int active = 0;
2103
37
    const char *env = config_get_env(config, "PYTHONPERFSUPPORT");
2104
37
    if (env) {
2105
0
        if (_Py_str_to_int(env, &active) != 0) {
2106
0
            active = 0;
2107
0
        }
2108
0
        if (active) {
2109
0
            config->perf_profiling = 1;
2110
0
        }
2111
0
    }
2112
37
    const wchar_t *xoption = config_get_xoption(config, L"perf");
2113
37
    if (xoption) {
2114
0
        config->perf_profiling = 1;
2115
0
    }
2116
37
    env = config_get_env(config, "PYTHON_PERF_JIT_SUPPORT");
2117
37
    if (env) {
2118
0
        if (_Py_str_to_int(env, &active) != 0) {
2119
0
            active = 0;
2120
0
        }
2121
0
        if (active) {
2122
0
            config->perf_profiling = 2;
2123
0
        }
2124
0
    }
2125
37
    xoption = config_get_xoption(config, L"perf_jit");
2126
37
    if (xoption) {
2127
0
        config->perf_profiling = 2;
2128
0
    }
2129
2130
37
    return _PyStatus_OK();
2131
2132
37
}
2133
2134
static PyStatus
2135
config_init_remote_debug(PyConfig *config)
2136
37
{
2137
#ifndef Py_REMOTE_DEBUG
2138
    config->remote_debug = 0;
2139
#else
2140
37
    int active = 1;
2141
37
    const char *env = Py_GETENV("PYTHON_DISABLE_REMOTE_DEBUG");
2142
37
    if (env) {
2143
0
        active = 0;
2144
0
    }
2145
37
    const wchar_t *xoption = config_get_xoption(config, L"disable-remote-debug");
2146
37
    if (xoption) {
2147
0
        active = 0;
2148
0
    }
2149
2150
37
    config->remote_debug = active;
2151
37
#endif
2152
37
    return _PyStatus_OK();
2153
2154
37
}
2155
2156
static PyStatus
2157
config_init_tracemalloc(PyConfig *config)
2158
37
{
2159
37
    int nframe;
2160
37
    int valid;
2161
2162
37
    const char *env = config_get_env(config, "PYTHONTRACEMALLOC");
2163
37
    if (env) {
2164
0
        if (!_Py_str_to_int(env, &nframe)) {
2165
0
            valid = (nframe >= 0);
2166
0
        }
2167
0
        else {
2168
0
            valid = 0;
2169
0
        }
2170
0
        if (!valid) {
2171
0
            return _PyStatus_ERR("PYTHONTRACEMALLOC: invalid number of frames");
2172
0
        }
2173
0
        config->tracemalloc = nframe;
2174
0
    }
2175
2176
37
    const wchar_t *xoption = config_get_xoption(config, L"tracemalloc");
2177
37
    if (xoption) {
2178
0
        const wchar_t *sep = wcschr(xoption, L'=');
2179
0
        if (sep) {
2180
0
            if (!config_wstr_to_int(sep + 1, &nframe)) {
2181
0
                valid = (nframe >= 0);
2182
0
            }
2183
0
            else {
2184
0
                valid = 0;
2185
0
            }
2186
0
            if (!valid) {
2187
0
                return _PyStatus_ERR("-X tracemalloc=NFRAME: "
2188
0
                                     "invalid number of frames");
2189
0
            }
2190
0
        }
2191
0
        else {
2192
            /* -X tracemalloc behaves as -X tracemalloc=1 */
2193
0
            nframe = 1;
2194
0
        }
2195
0
        config->tracemalloc = nframe;
2196
0
    }
2197
37
    return _PyStatus_OK();
2198
37
}
2199
2200
static PyStatus
2201
config_init_int_max_str_digits(PyConfig *config)
2202
37
{
2203
37
    int maxdigits;
2204
2205
37
    const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS");
2206
37
    if (env) {
2207
0
        bool valid = 0;
2208
0
        if (!_Py_str_to_int(env, &maxdigits)) {
2209
0
            valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD));
2210
0
        }
2211
0
        if (!valid) {
2212
0
#define STRINGIFY(VAL) _STRINGIFY(VAL)
2213
0
#define _STRINGIFY(VAL) #VAL
2214
0
            return _PyStatus_ERR(
2215
0
                    "PYTHONINTMAXSTRDIGITS: invalid limit; must be >= "
2216
0
                    STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD)
2217
0
                    " or 0 for unlimited.");
2218
0
        }
2219
0
        config->int_max_str_digits = maxdigits;
2220
0
    }
2221
2222
37
    const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits");
2223
37
    if (xoption) {
2224
0
        const wchar_t *sep = wcschr(xoption, L'=');
2225
0
        bool valid = 0;
2226
0
        if (sep) {
2227
0
            if (!config_wstr_to_int(sep + 1, &maxdigits)) {
2228
0
                valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD));
2229
0
            }
2230
0
        }
2231
0
        if (!valid) {
2232
0
            return _PyStatus_ERR(
2233
0
                    "-X int_max_str_digits: invalid limit; must be >= "
2234
0
                    STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD)
2235
0
                    " or 0 for unlimited.");
2236
0
#undef _STRINGIFY
2237
0
#undef STRINGIFY
2238
0
        }
2239
0
        config->int_max_str_digits = maxdigits;
2240
0
    }
2241
37
    if (config->int_max_str_digits < 0) {
2242
37
        config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS;
2243
37
    }
2244
37
    return _PyStatus_OK();
2245
37
}
2246
2247
static PyStatus
2248
config_init_pycache_prefix(PyConfig *config)
2249
37
{
2250
37
    assert(config->pycache_prefix == NULL);
2251
2252
37
    const wchar_t *xoption = config_get_xoption(config, L"pycache_prefix");
2253
37
    if (xoption) {
2254
0
        const wchar_t *sep = wcschr(xoption, L'=');
2255
0
        if (sep && wcslen(sep) > 1) {
2256
0
            config->pycache_prefix = _PyMem_RawWcsdup(sep + 1);
2257
0
            if (config->pycache_prefix == NULL) {
2258
0
                return _PyStatus_NO_MEMORY();
2259
0
            }
2260
0
        }
2261
0
        else {
2262
            // PYTHONPYCACHEPREFIX env var ignored
2263
            // if "-X pycache_prefix=" option is used
2264
0
            config->pycache_prefix = NULL;
2265
0
        }
2266
0
        return _PyStatus_OK();
2267
0
    }
2268
2269
37
    return CONFIG_GET_ENV_DUP(config, &config->pycache_prefix,
2270
37
                              L"PYTHONPYCACHEPREFIX",
2271
37
                              "PYTHONPYCACHEPREFIX");
2272
37
}
2273
2274
2275
#ifdef Py_DEBUG
2276
static PyStatus
2277
config_init_run_presite(PyConfig *config)
2278
{
2279
    assert(config->run_presite == NULL);
2280
2281
    const wchar_t *xoption = config_get_xoption(config, L"presite");
2282
    if (xoption) {
2283
        const wchar_t *sep = wcschr(xoption, L'=');
2284
        if (sep && wcslen(sep) > 1) {
2285
            config->run_presite = _PyMem_RawWcsdup(sep + 1);
2286
            if (config->run_presite == NULL) {
2287
                return _PyStatus_NO_MEMORY();
2288
            }
2289
        }
2290
        else {
2291
            // PYTHON_PRESITE env var ignored
2292
            // if "-X presite=" option is used
2293
            config->run_presite = NULL;
2294
        }
2295
        return _PyStatus_OK();
2296
    }
2297
2298
    return CONFIG_GET_ENV_DUP(config, &config->run_presite,
2299
                              L"PYTHON_PRESITE",
2300
                              "PYTHON_PRESITE");
2301
}
2302
#endif
2303
2304
static PyStatus
2305
config_init_import_time(PyConfig *config)
2306
37
{
2307
37
    int importtime = 0;
2308
2309
37
    const char *env = config_get_env(config, "PYTHONPROFILEIMPORTTIME");
2310
37
    if (env) {
2311
0
        if (_Py_str_to_int(env, &importtime) != 0) {
2312
0
            importtime = 1;
2313
0
        }
2314
0
        if (importtime < 0 || importtime > 2) {
2315
0
            return _PyStatus_ERR(
2316
0
                "PYTHONPROFILEIMPORTTIME: numeric values other than 1 and 2 "
2317
0
                "are reserved for future use.");
2318
0
        }
2319
0
    }
2320
2321
37
    const wchar_t *x_value = config_get_xoption_value(config, L"importtime");
2322
37
    if (x_value) {
2323
0
        if (*x_value == 0 || config_wstr_to_int(x_value, &importtime) != 0) {
2324
0
            importtime = 1;
2325
0
        }
2326
0
        if (importtime < 0 || importtime > 2) {
2327
0
            return _PyStatus_ERR(
2328
0
                "-X importtime: values other than 1 and 2 "
2329
0
                "are reserved for future use.");
2330
0
        }
2331
0
    }
2332
2333
37
    config->import_time = importtime;
2334
37
    return _PyStatus_OK();
2335
37
}
2336
2337
static PyStatus
2338
config_init_lazy_imports(PyConfig *config)
2339
37
{
2340
37
    int lazy_imports = -1;
2341
2342
37
    const char *env = config_get_env(config, "PYTHON_LAZY_IMPORTS");
2343
37
    if (env) {
2344
0
        if (strcmp(env, "all") == 0) {
2345
0
            lazy_imports = 1;
2346
0
        }
2347
0
        else if (strcmp(env, "normal") == 0) {
2348
0
            lazy_imports = -1;
2349
0
        }
2350
0
        else {
2351
0
            return _PyStatus_ERR("PYTHON_LAZY_IMPORTS: invalid value; "
2352
0
                                 "expected 'all' or 'normal'");
2353
0
        }
2354
0
        config->lazy_imports = lazy_imports;
2355
0
    }
2356
2357
37
    const wchar_t *x_value = config_get_xoption_value(config, L"lazy_imports");
2358
37
    if (x_value) {
2359
0
        if (wcscmp(x_value, L"all") == 0) {
2360
0
            lazy_imports = 1;
2361
0
        }
2362
0
        else if (wcscmp(x_value, L"normal") == 0) {
2363
0
            lazy_imports = -1;
2364
0
        }
2365
0
        else {
2366
0
            return _PyStatus_ERR("-X lazy_imports: invalid value; "
2367
0
                                 "expected 'all' or 'normal'");
2368
0
        }
2369
0
        config->lazy_imports = lazy_imports;
2370
0
    }
2371
37
    return _PyStatus_OK();
2372
37
}
2373
2374
static PyStatus
2375
config_init_pathconfig_warnings(PyConfig *config)
2376
37
{
2377
37
    const char *env = config_get_env(config, "PYTHON_PATHCONFIG_WARNINGS");
2378
37
    if (env) {
2379
0
        int enabled;
2380
0
        if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
2381
0
            return _PyStatus_ERR(
2382
0
                "PYTHON_PATHCONFIG_WARNINGS=N: N is missing or invalid");
2383
0
        }
2384
0
        config->pathconfig_warnings = enabled;
2385
0
    }
2386
2387
37
    const wchar_t *xoption = config_get_xoption(config, L"pathconfig_warnings");
2388
37
    if (xoption) {
2389
0
        int enabled;
2390
0
        const wchar_t *sep = wcschr(xoption, L'=');
2391
0
        if (!sep || (config_wstr_to_int(sep + 1, &enabled) < 0) || (enabled < 0) || (enabled > 1)) {
2392
0
            return _PyStatus_ERR(
2393
0
                "-X pathconfig_warnings=n: n is missing or invalid");
2394
0
        }
2395
0
        config->pathconfig_warnings = enabled;
2396
0
    }
2397
37
    return _PyStatus_OK();
2398
37
}
2399
2400
static PyStatus
2401
config_read_complex_options(PyConfig *config)
2402
37
{
2403
    /* More complex options configured by env var and -X option */
2404
37
    if (config->faulthandler < 0) {
2405
37
        if (config_get_env(config, "PYTHONFAULTHANDLER")
2406
37
           || config_get_xoption(config, L"faulthandler")) {
2407
0
            config->faulthandler = 1;
2408
0
        }
2409
37
    }
2410
37
    if (config_get_env(config, "PYTHONNODEBUGRANGES")
2411
37
       || config_get_xoption(config, L"no_debug_ranges")) {
2412
0
        config->code_debug_ranges = 0;
2413
0
    }
2414
2415
37
    PyStatus status;
2416
37
    if (config->import_time < 0) {
2417
37
        status = config_init_import_time(config);
2418
37
        if (_PyStatus_EXCEPTION(status)) {
2419
0
            return status;
2420
0
        }
2421
37
    }
2422
2423
37
    if (config->lazy_imports < 0) {
2424
37
        status = config_init_lazy_imports(config);
2425
37
        if (_PyStatus_EXCEPTION(status)) {
2426
0
            return status;
2427
0
        }
2428
37
    }
2429
2430
37
    if (config->tracemalloc < 0) {
2431
37
        status = config_init_tracemalloc(config);
2432
37
        if (_PyStatus_EXCEPTION(status)) {
2433
0
            return status;
2434
0
        }
2435
37
    }
2436
2437
37
    if (config->perf_profiling < 0) {
2438
37
        status = config_init_perf_profiling(config);
2439
37
        if (_PyStatus_EXCEPTION(status)) {
2440
0
            return status;
2441
0
        }
2442
37
    }
2443
2444
37
    if (config->remote_debug < 0) {
2445
37
        status = config_init_remote_debug(config);
2446
37
        if (_PyStatus_EXCEPTION(status)) {
2447
0
            return status;
2448
0
        }
2449
37
    }
2450
2451
37
    if (config->int_max_str_digits < 0) {
2452
37
        status = config_init_int_max_str_digits(config);
2453
37
        if (_PyStatus_EXCEPTION(status)) {
2454
0
            return status;
2455
0
        }
2456
37
    }
2457
2458
37
    if (config->cpu_count < 0) {
2459
37
        status = config_init_cpu_count(config);
2460
37
        if (_PyStatus_EXCEPTION(status)) {
2461
0
            return status;
2462
0
        }
2463
37
    }
2464
2465
37
    if (config->pycache_prefix == NULL) {
2466
37
        status = config_init_pycache_prefix(config);
2467
37
        if (_PyStatus_EXCEPTION(status)) {
2468
0
            return status;
2469
0
        }
2470
37
    }
2471
2472
#ifdef Py_DEBUG
2473
    if (config->run_presite == NULL) {
2474
        status = config_init_run_presite(config);
2475
        if (_PyStatus_EXCEPTION(status)) {
2476
            return status;
2477
        }
2478
    }
2479
#endif
2480
2481
37
    status = config_init_thread_inherit_context(config);
2482
37
    if (_PyStatus_EXCEPTION(status)) {
2483
0
        return status;
2484
0
    }
2485
2486
37
    status = config_init_context_aware_warnings(config);
2487
37
    if (_PyStatus_EXCEPTION(status)) {
2488
0
        return status;
2489
0
    }
2490
2491
37
    status = config_init_tlbc(config);
2492
37
    if (_PyStatus_EXCEPTION(status)) {
2493
0
        return status;
2494
0
    }
2495
2496
37
    status = config_init_pathconfig_warnings(config);
2497
37
    if (_PyStatus_EXCEPTION(status)) {
2498
0
        return status;
2499
0
    }
2500
2501
37
    return _PyStatus_OK();
2502
37
}
2503
2504
2505
static const wchar_t *
2506
config_get_stdio_errors(const PyPreConfig *preconfig)
2507
37
{
2508
37
    if (preconfig->utf8_mode) {
2509
        /* UTF-8 Mode uses UTF-8/surrogateescape */
2510
37
        return L"surrogateescape";
2511
37
    }
2512
2513
0
#ifndef MS_WINDOWS
2514
0
    const char *loc = setlocale(LC_CTYPE, NULL);
2515
0
    if (loc != NULL) {
2516
        /* surrogateescape is the default in the legacy C and POSIX locales */
2517
0
        if (strcmp(loc, "C") == 0 || strcmp(loc, "POSIX") == 0) {
2518
0
            return L"surrogateescape";
2519
0
        }
2520
2521
0
#ifdef PY_COERCE_C_LOCALE
2522
        /* surrogateescape is the default in locale coercion target locales */
2523
0
        if (_Py_IsLocaleCoercionTarget(loc)) {
2524
0
            return L"surrogateescape";
2525
0
        }
2526
0
#endif
2527
0
    }
2528
2529
0
    return L"strict";
2530
#else
2531
    /* On Windows, always use surrogateescape by default */
2532
    return L"surrogateescape";
2533
#endif
2534
0
}
2535
2536
2537
// See also config_get_fs_encoding()
2538
static PyStatus
2539
config_get_locale_encoding(PyConfig *config, const PyPreConfig *preconfig,
2540
                           wchar_t **locale_encoding)
2541
37
{
2542
37
    wchar_t *encoding;
2543
37
    if (preconfig->utf8_mode) {
2544
37
        encoding = _PyMem_RawWcsdup(L"utf-8");
2545
37
    }
2546
0
    else {
2547
0
        encoding = _Py_GetLocaleEncoding();
2548
0
    }
2549
37
    if (encoding == NULL) {
2550
0
        return _PyStatus_NO_MEMORY();
2551
0
    }
2552
37
    PyStatus status = PyConfig_SetString(config, locale_encoding, encoding);
2553
37
    PyMem_RawFree(encoding);
2554
37
    return status;
2555
37
}
2556
2557
2558
static PyStatus
2559
config_init_stdio_encoding(PyConfig *config,
2560
                           const PyPreConfig *preconfig)
2561
37
{
2562
37
    PyStatus status;
2563
2564
    // Exit if encoding and errors are defined
2565
37
    if (config->stdio_encoding != NULL && config->stdio_errors != NULL) {
2566
0
        return _PyStatus_OK();
2567
0
    }
2568
2569
    /* PYTHONIOENCODING environment variable */
2570
37
    const char *opt = config_get_env(config, "PYTHONIOENCODING");
2571
37
    if (opt) {
2572
0
        char *pythonioencoding = _PyMem_RawStrdup(opt);
2573
0
        if (pythonioencoding == NULL) {
2574
0
            return _PyStatus_NO_MEMORY();
2575
0
        }
2576
2577
0
        char *errors = strchr(pythonioencoding, ':');
2578
0
        if (errors) {
2579
0
            *errors = '\0';
2580
0
            errors++;
2581
0
            if (!errors[0]) {
2582
0
                errors = NULL;
2583
0
            }
2584
0
        }
2585
2586
        /* Does PYTHONIOENCODING contain an encoding? */
2587
0
        if (pythonioencoding[0]) {
2588
0
            if (config->stdio_encoding == NULL) {
2589
0
                status = CONFIG_SET_BYTES_STR(config, &config->stdio_encoding,
2590
0
                                              pythonioencoding,
2591
0
                                              "PYTHONIOENCODING environment variable");
2592
0
                if (_PyStatus_EXCEPTION(status)) {
2593
0
                    PyMem_RawFree(pythonioencoding);
2594
0
                    return status;
2595
0
                }
2596
0
            }
2597
2598
            /* If the encoding is set but not the error handler,
2599
               use "strict" error handler by default.
2600
               PYTHONIOENCODING=latin1 behaves as
2601
               PYTHONIOENCODING=latin1:strict. */
2602
0
            if (!errors) {
2603
0
                errors = "strict";
2604
0
            }
2605
0
        }
2606
2607
0
        if (config->stdio_errors == NULL && errors != NULL) {
2608
0
            status = CONFIG_SET_BYTES_STR(config, &config->stdio_errors,
2609
0
                                          errors,
2610
0
                                          "PYTHONIOENCODING environment variable");
2611
0
            if (_PyStatus_EXCEPTION(status)) {
2612
0
                PyMem_RawFree(pythonioencoding);
2613
0
                return status;
2614
0
            }
2615
0
        }
2616
2617
0
        PyMem_RawFree(pythonioencoding);
2618
0
    }
2619
2620
    /* Choose the default error handler based on the current locale. */
2621
37
    if (config->stdio_encoding == NULL
2622
#ifdef MS_WINDOWS
2623
        /* gh-86427: it is determined for each stream: create_stdio() uses
2624
           _Py_device_encoding(), falling back to the locale encoding. */
2625
        && !config->legacy_windows_stdio
2626
#endif
2627
37
       ) {
2628
37
        status = config_get_locale_encoding(config, preconfig,
2629
37
                                            &config->stdio_encoding);
2630
37
        if (_PyStatus_EXCEPTION(status)) {
2631
0
            return status;
2632
0
        }
2633
37
    }
2634
37
    if (config->stdio_errors == NULL) {
2635
37
        const wchar_t *errors = config_get_stdio_errors(preconfig);
2636
37
        assert(errors != NULL);
2637
2638
37
        status = PyConfig_SetString(config, &config->stdio_errors, errors);
2639
37
        if (_PyStatus_EXCEPTION(status)) {
2640
0
            return status;
2641
0
        }
2642
37
    }
2643
2644
37
    return _PyStatus_OK();
2645
37
}
2646
2647
2648
// See also config_get_locale_encoding()
2649
static PyStatus
2650
config_get_fs_encoding(PyConfig *config, const PyPreConfig *preconfig,
2651
                       wchar_t **fs_encoding)
2652
37
{
2653
#ifdef _Py_FORCE_UTF8_FS_ENCODING
2654
    return PyConfig_SetString(config, fs_encoding, L"utf-8");
2655
#elif defined(MS_WINDOWS)
2656
    const wchar_t *encoding;
2657
    if (preconfig->legacy_windows_fs_encoding) {
2658
        // Legacy Windows filesystem encoding: mbcs/replace
2659
        encoding = L"mbcs";
2660
    }
2661
    else {
2662
        // Windows defaults to utf-8/surrogatepass (PEP 529)
2663
        encoding = L"utf-8";
2664
    }
2665
     return PyConfig_SetString(config, fs_encoding, encoding);
2666
#else  // !MS_WINDOWS
2667
37
    if (preconfig->utf8_mode) {
2668
37
        return PyConfig_SetString(config, fs_encoding, L"utf-8");
2669
37
    }
2670
2671
0
    if (_Py_GetForceASCII()) {
2672
0
        return PyConfig_SetString(config, fs_encoding, L"ascii");
2673
0
    }
2674
2675
0
    return config_get_locale_encoding(config, preconfig, fs_encoding);
2676
0
#endif  // !MS_WINDOWS
2677
0
}
2678
2679
2680
static PyStatus
2681
config_init_fs_encoding(PyConfig *config, const PyPreConfig *preconfig)
2682
37
{
2683
37
    PyStatus status;
2684
2685
37
    if (config->filesystem_encoding == NULL) {
2686
37
        status = config_get_fs_encoding(config, preconfig,
2687
37
                                        &config->filesystem_encoding);
2688
37
        if (_PyStatus_EXCEPTION(status)) {
2689
0
            return status;
2690
0
        }
2691
37
    }
2692
2693
37
    if (config->filesystem_errors == NULL) {
2694
37
        const wchar_t *errors;
2695
#ifdef MS_WINDOWS
2696
        if (preconfig->legacy_windows_fs_encoding) {
2697
            errors = L"replace";
2698
        }
2699
        else {
2700
            errors = L"surrogatepass";
2701
        }
2702
#else
2703
37
        errors = L"surrogateescape";
2704
37
#endif
2705
37
        status = PyConfig_SetString(config, &config->filesystem_errors, errors);
2706
37
        if (_PyStatus_EXCEPTION(status)) {
2707
0
            return status;
2708
0
        }
2709
37
    }
2710
37
    return _PyStatus_OK();
2711
37
}
2712
2713
2714
static PyStatus
2715
config_init_import(PyConfig *config, int compute_path_config)
2716
74
{
2717
74
    PyStatus status;
2718
2719
74
    status = _PyConfig_InitPathConfig(config, compute_path_config);
2720
74
    if (_PyStatus_EXCEPTION(status)) {
2721
0
        return status;
2722
0
    }
2723
2724
74
    const char *env = config_get_env(config, "PYTHON_FROZEN_MODULES");
2725
74
    if (env == NULL) {
2726
74
    }
2727
0
    else if (strcmp(env, "on") == 0) {
2728
0
        config->use_frozen_modules = 1;
2729
0
    }
2730
0
    else if (strcmp(env, "off") == 0) {
2731
0
        config->use_frozen_modules = 0;
2732
0
    } else {
2733
0
        return PyStatus_Error("bad value for PYTHON_FROZEN_MODULES "
2734
0
                              "(expected \"on\" or \"off\")");
2735
0
    }
2736
2737
    /* -X frozen_modules=[on|off] */
2738
74
    const wchar_t *value = config_get_xoption_value(config, L"frozen_modules");
2739
74
    if (value == NULL) {
2740
74
    }
2741
0
    else if (wcscmp(value, L"on") == 0) {
2742
0
        config->use_frozen_modules = 1;
2743
0
    }
2744
0
    else if (wcscmp(value, L"off") == 0) {
2745
0
        config->use_frozen_modules = 0;
2746
0
    }
2747
0
    else if (wcslen(value) == 0) {
2748
        // "-X frozen_modules" and "-X frozen_modules=" both imply "on".
2749
0
        config->use_frozen_modules = 1;
2750
0
    }
2751
0
    else {
2752
0
        return PyStatus_Error("bad value for option -X frozen_modules "
2753
0
                              "(expected \"on\" or \"off\")");
2754
0
    }
2755
2756
74
    assert(config->use_frozen_modules >= 0);
2757
74
    return _PyStatus_OK();
2758
74
}
2759
2760
PyStatus
2761
_PyConfig_InitImportConfig(PyConfig *config)
2762
37
{
2763
37
    return config_init_import(config, 1);
2764
37
}
2765
2766
2767
static PyStatus
2768
config_read(PyConfig *config, int compute_path_config)
2769
37
{
2770
37
    PyStatus status;
2771
37
    const PyPreConfig *preconfig = &_PyRuntime.preconfig;
2772
2773
37
    if (config->use_environment) {
2774
37
        status = config_read_env_vars(config);
2775
37
        if (_PyStatus_EXCEPTION(status)) {
2776
0
            return status;
2777
0
        }
2778
37
    }
2779
2780
    /* -X options */
2781
37
    if (config_get_xoption(config, L"showrefcount")) {
2782
0
        config->show_ref_count = 1;
2783
0
    }
2784
2785
37
    const wchar_t *x_gil = config_get_xoption_value(config, L"gil");
2786
37
    if (x_gil != NULL) {
2787
0
        size_t len = wcslen(x_gil);
2788
0
        status = config_read_gil(config, len, x_gil[0]);
2789
0
        if (_PyStatus_EXCEPTION(status)) {
2790
0
            return status;
2791
0
        }
2792
0
    }
2793
2794
#ifdef Py_STATS
2795
    if (config_get_xoption(config, L"pystats")) {
2796
        config->_pystats = 1;
2797
    }
2798
    else if (config_get_env(config, "PYTHONSTATS")) {
2799
        config->_pystats = 1;
2800
    }
2801
    if (config->_pystats < 0) {
2802
        config->_pystats = 0;
2803
    }
2804
#endif
2805
2806
37
    status = config_read_complex_options(config);
2807
37
    if (_PyStatus_EXCEPTION(status)) {
2808
0
        return status;
2809
0
    }
2810
2811
37
    if (config->_install_importlib) {
2812
37
        status = config_init_import(config, compute_path_config);
2813
37
        if (_PyStatus_EXCEPTION(status)) {
2814
0
            return status;
2815
0
        }
2816
37
    }
2817
2818
    /* default values */
2819
37
    if (config->dev_mode) {
2820
0
        if (config->faulthandler < 0) {
2821
0
            config->faulthandler = 1;
2822
0
        }
2823
0
    }
2824
37
    if (config->faulthandler < 0) {
2825
37
        config->faulthandler = 0;
2826
37
    }
2827
37
    if (config->tracemalloc < 0) {
2828
37
        config->tracemalloc = 0;
2829
37
    }
2830
37
    if (config->lazy_imports < 0) {
2831
37
        config->lazy_imports = -1;  // Default is auto/unset
2832
37
    }
2833
37
    if (config->perf_profiling < 0) {
2834
37
        config->perf_profiling = 0;
2835
37
    }
2836
37
    if (config->remote_debug < 0) {
2837
0
        config->remote_debug = -1;
2838
0
    }
2839
37
    if (config->use_hash_seed < 0) {
2840
0
        config->use_hash_seed = 0;
2841
0
        config->hash_seed = 0;
2842
0
    }
2843
2844
37
    if (config->filesystem_encoding == NULL || config->filesystem_errors == NULL) {
2845
37
        status = config_init_fs_encoding(config, preconfig);
2846
37
        if (_PyStatus_EXCEPTION(status)) {
2847
0
            return status;
2848
0
        }
2849
37
    }
2850
2851
37
    status = config_init_stdio_encoding(config, preconfig);
2852
37
    if (_PyStatus_EXCEPTION(status)) {
2853
0
        return status;
2854
0
    }
2855
2856
37
    if (config->argv.length < 1) {
2857
        /* Ensure at least one (empty) argument is seen */
2858
37
        status = PyWideStringList_Append(&config->argv, L"");
2859
37
        if (_PyStatus_EXCEPTION(status)) {
2860
0
            return status;
2861
0
        }
2862
37
    }
2863
2864
37
    if (config->check_hash_pycs_mode == NULL) {
2865
37
        status = PyConfig_SetString(config, &config->check_hash_pycs_mode,
2866
37
                                    L"default");
2867
37
        if (_PyStatus_EXCEPTION(status)) {
2868
0
            return status;
2869
0
        }
2870
37
    }
2871
2872
37
    if (config->configure_c_stdio < 0) {
2873
0
        config->configure_c_stdio = 1;
2874
0
    }
2875
2876
    // Only parse arguments once.
2877
37
    if (config->parse_argv == 1) {
2878
0
        config->parse_argv = 2;
2879
0
    }
2880
2881
37
    return _PyStatus_OK();
2882
37
}
2883
2884
2885
static void
2886
config_init_stdio(const PyConfig *config)
2887
0
{
2888
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
2889
    /* don't translate newlines (\r\n <=> \n) */
2890
    _setmode(fileno(stdin), O_BINARY);
2891
    _setmode(fileno(stdout), O_BINARY);
2892
    _setmode(fileno(stderr), O_BINARY);
2893
#endif
2894
2895
0
    if (!config->buffered_stdio) {
2896
0
#ifdef HAVE_SETVBUF
2897
0
        setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
2898
0
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
2899
0
        setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
2900
#else /* !HAVE_SETVBUF */
2901
        setbuf(stdin,  (char *)NULL);
2902
        setbuf(stdout, (char *)NULL);
2903
        setbuf(stderr, (char *)NULL);
2904
#endif /* !HAVE_SETVBUF */
2905
0
    }
2906
0
    else if (config->interactive) {
2907
#ifdef MS_WINDOWS
2908
        /* Doesn't have to have line-buffered -- use unbuffered */
2909
        /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
2910
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
2911
#else /* !MS_WINDOWS */
2912
0
#ifdef HAVE_SETVBUF
2913
0
        setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
2914
0
        setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
2915
0
#endif /* HAVE_SETVBUF */
2916
0
#endif /* !MS_WINDOWS */
2917
        /* Leave stderr alone - it should be unbuffered anyway. */
2918
0
    }
2919
0
}
2920
2921
2922
/* Write the configuration:
2923
2924
   - set Py_xxx global configuration variables
2925
   - initialize C standard streams (stdin, stdout, stderr) */
2926
PyStatus
2927
_PyConfig_Write(const PyConfig *config, _PyRuntimeState *runtime)
2928
37
{
2929
37
    if (config->configure_c_stdio) {
2930
0
        config_init_stdio(config);
2931
0
    }
2932
2933
    /* Write the new pre-configuration into _PyRuntime */
2934
37
    PyPreConfig *preconfig = &runtime->preconfig;
2935
37
    preconfig->isolated = config->isolated;
2936
37
    preconfig->use_environment = config->use_environment;
2937
37
    preconfig->dev_mode = config->dev_mode;
2938
2939
37
    if (_Py_SetArgcArgv(config->orig_argv.length,
2940
37
                        config->orig_argv.items) < 0)
2941
0
    {
2942
0
        return _PyStatus_NO_MEMORY();
2943
0
    }
2944
2945
#ifdef PYMALLOC_USE_HUGEPAGES
2946
    runtime->allocators.use_hugepages = config->pymalloc_hugepages;
2947
#endif
2948
2949
37
    return _PyStatus_OK();
2950
37
}
2951
2952
2953
/* --- PyConfig command line parser -------------------------- */
2954
2955
static void
2956
config_usage(int error, const wchar_t* program)
2957
0
{
2958
0
    FILE *f = error ? stderr : stdout;
2959
0
    int colorize = _Py_can_colorize(f);
2960
2961
0
    fprint_help(f, usage_line, colorize, program);
2962
0
    if (error) {
2963
0
        fprintf(f, "Try `python -h' for more information.\n");
2964
0
    }
2965
0
    else {
2966
0
        fprint_help(f, usage_help, colorize, NULL);
2967
0
    }
2968
0
}
2969
2970
static void
2971
config_envvars_usage(void)
2972
0
{
2973
0
    int colorize = _Py_can_colorize(stdout);
2974
0
    fprint_help(stdout, usage_envvars, colorize, NULL);
2975
0
}
2976
2977
static void
2978
config_xoptions_usage(void)
2979
0
{
2980
0
    int colorize = _Py_can_colorize(stdout);
2981
0
    fprint_help(stdout, usage_xoptions, colorize, NULL);
2982
0
}
2983
2984
static void
2985
config_complete_usage(const wchar_t* program)
2986
0
{
2987
0
   config_usage(0, program);
2988
0
   putchar('\n');
2989
0
   config_envvars_usage();
2990
0
   putchar('\n');
2991
0
   config_xoptions_usage();
2992
0
}
2993
2994
2995
/* Parse the command line arguments */
2996
static PyStatus
2997
config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
2998
                     Py_ssize_t *opt_index)
2999
0
{
3000
    // Only store the first option
3001
0
#define DEFER_OPTION(OPTION) \
3002
0
        do { \
3003
0
            if (config->_deferred_cmdline_option == 0) { \
3004
0
                config->_deferred_cmdline_option = (OPTION); \
3005
0
            } \
3006
0
        } while (0)
3007
3008
0
    PyStatus status;
3009
0
    const PyWideStringList *argv = &config->argv;
3010
0
    int print_version = 0;
3011
3012
0
    struct _PyOS_GetOpt getopt;
3013
0
    _PyOS_GetOpt_Init(&getopt, argv->length, argv->items);
3014
0
    do {
3015
0
        int c = _PyOS_GetOpt(&getopt);
3016
0
        if (c == -1) {
3017
0
            break;
3018
0
        }
3019
3020
0
        if (c == 'c') {
3021
0
            if (config->run_command == NULL) {
3022
                /* -c is the last option; following arguments
3023
                   that look like options are left for the
3024
                   command to interpret. */
3025
0
                size_t len = wcslen(getopt.arg) + 1 + 1;
3026
0
                wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
3027
0
                if (command == NULL) {
3028
0
                    return _PyStatus_NO_MEMORY();
3029
0
                }
3030
0
                memcpy(command, getopt.arg, (len - 2) * sizeof(wchar_t));
3031
0
                command[len - 2] = '\n';
3032
0
                command[len - 1] = 0;
3033
0
                config->run_command = command;
3034
0
            }
3035
0
            break;
3036
0
        }
3037
3038
0
        if (c == 'm') {
3039
            /* -m is the last option; following arguments
3040
               that look like options are left for the
3041
               module to interpret. */
3042
0
            if (config->run_module == NULL) {
3043
0
                config->run_module = _PyMem_RawWcsdup(getopt.arg);
3044
0
                if (config->run_module == NULL) {
3045
0
                    return _PyStatus_NO_MEMORY();
3046
0
                }
3047
0
            }
3048
0
            break;
3049
0
        }
3050
3051
0
        switch (c) {
3052
        // Integers represent long options, see Python/getopt.c
3053
0
        case 1:
3054
            // --check-hash-based-pycs option
3055
0
            if (wcscmp(getopt.arg, L"always") == 0
3056
0
                || wcscmp(getopt.arg, L"never") == 0
3057
0
                || wcscmp(getopt.arg, L"default") == 0)
3058
0
            {
3059
0
                status = PyConfig_SetString(config, &config->check_hash_pycs_mode,
3060
0
                                            getopt.arg);
3061
0
                if (_PyStatus_EXCEPTION(status)) {
3062
0
                    return status;
3063
0
                }
3064
0
            } else {
3065
0
                DEFER_OPTION(c);
3066
0
            }
3067
0
            break;
3068
3069
0
        case 2:
3070
            // --help-all option
3071
0
            DEFER_OPTION(c);
3072
0
            break;
3073
3074
0
        case 3:
3075
            // --help-env option
3076
0
            DEFER_OPTION(c);
3077
0
            break;
3078
3079
0
        case 4:
3080
            // --help-xoptions option
3081
0
            DEFER_OPTION(c);
3082
0
            break;
3083
3084
0
        case 'b':
3085
0
            config->bytes_warning++;
3086
0
            break;
3087
3088
0
        case 'd':
3089
0
            config->parser_debug++;
3090
0
            break;
3091
3092
0
        case 'i':
3093
0
            config->inspect++;
3094
0
            config->interactive++;
3095
0
            break;
3096
3097
0
        case 'E':
3098
0
        case 'I':
3099
0
        case 'X':
3100
            /* option handled by _PyPreCmdline_Read() */
3101
0
            break;
3102
3103
0
        case 'O':
3104
0
            config->optimization_level++;
3105
0
            break;
3106
3107
0
        case 'P':
3108
0
            config->safe_path = 1;
3109
0
            break;
3110
3111
0
        case 'B':
3112
0
            config->write_bytecode = 0;
3113
0
            break;
3114
3115
0
        case 's':
3116
0
            config->user_site_directory = 0;
3117
0
            break;
3118
3119
0
        case 'S':
3120
0
            config->site_import = 0;
3121
0
            break;
3122
3123
0
        case 't':
3124
            /* ignored for backwards compatibility */
3125
0
            break;
3126
3127
0
        case 'u':
3128
0
            config->buffered_stdio = 0;
3129
0
            break;
3130
3131
0
        case 'v':
3132
0
            config->verbose++;
3133
0
            break;
3134
3135
0
        case 'x':
3136
0
            config->skip_source_first_line = 1;
3137
0
            break;
3138
3139
0
        case 'h':
3140
0
        case '?':
3141
0
            DEFER_OPTION(c);
3142
0
            break;
3143
3144
0
        case 'V':
3145
0
            print_version++;
3146
0
            break;
3147
3148
0
        case 'W':
3149
0
            status = PyWideStringList_Append(warnoptions, getopt.arg);
3150
0
            if (_PyStatus_EXCEPTION(status)) {
3151
0
                return status;
3152
0
            }
3153
0
            break;
3154
3155
0
        case 'q':
3156
0
            config->quiet++;
3157
0
            break;
3158
3159
0
        case 'R':
3160
0
            config->use_hash_seed = 0;
3161
0
            break;
3162
3163
        /* This space reserved for other options */
3164
3165
0
        default:
3166
            /* unknown argument: parsing failed */
3167
0
            DEFER_OPTION(c);
3168
0
            break;
3169
0
        }
3170
0
    } while (config->_deferred_cmdline_option == 0);
3171
3172
0
    if (print_version >= 2) {
3173
0
        DEFER_OPTION('W');
3174
0
    }
3175
0
    else if (print_version >= 1) {
3176
0
        DEFER_OPTION('V');
3177
0
    }
3178
3179
0
    if (config->run_command == NULL && config->run_module == NULL
3180
0
        && getopt.index < argv->length
3181
0
        && wcscmp(argv->items[getopt.index], L"-") != 0
3182
0
        && config->run_filename == NULL)
3183
0
    {
3184
0
        config->run_filename = _PyMem_RawWcsdup(argv->items[getopt.index]);
3185
0
        if (config->run_filename == NULL) {
3186
0
            return _PyStatus_NO_MEMORY();
3187
0
        }
3188
0
    }
3189
3190
0
    if (config->run_command != NULL || config->run_module != NULL) {
3191
        /* Backup getopt.index */
3192
0
        getopt.index--;
3193
0
    }
3194
3195
0
    *opt_index = getopt.index;
3196
3197
0
    return _PyStatus_OK();
3198
3199
0
#undef DEFER_OPTION
3200
0
}
3201
3202
3203
int
3204
_PyConfig_ProcessDeferredCmdlineOption(PyConfig *config)
3205
0
{
3206
0
    int c = config->_deferred_cmdline_option;
3207
0
    config->_deferred_cmdline_option = 0;
3208
0
    if (c == 0) {
3209
        // There is no deferred option
3210
0
        return -1;
3211
0
    }
3212
3213
    // Select the program name
3214
0
    const PyWideStringList *argv = &config->argv;
3215
0
    const wchar_t* program = config->program_name;
3216
0
    if (!program && argv->length >= 1) {
3217
0
        program = argv->items[0];
3218
0
    }
3219
0
    if (!program) {
3220
0
        program = L"python";
3221
0
    }
3222
3223
0
    switch (c) {
3224
0
    case 'h':
3225
0
    case '?':
3226
0
        config_usage(0, program);
3227
0
        return 0;
3228
3229
0
    case 'V':
3230
0
        printf("Python %s\n", PY_VERSION);
3231
0
        return 0;
3232
3233
0
    case 'W':  // -VV or more -V options
3234
0
        printf("Python %s\n", Py_GetVersion());
3235
0
        return 0;
3236
3237
    // Integers represent long options, see Python/getopt.c
3238
0
    case 1:
3239
        // check-hash-based-pycs
3240
0
        fprintf(stderr, "--check-hash-based-pycs must be one of "
3241
0
                "'default', 'always', or 'never'\n");
3242
0
        config_usage(1, program);
3243
0
        return 2;
3244
3245
0
    case 2:
3246
        // help-all
3247
0
        config_complete_usage(program);
3248
0
        return 0;
3249
3250
0
    case 3:
3251
        // help-env
3252
0
        config_envvars_usage();
3253
0
        return 0;
3254
3255
0
    case 4:
3256
        // help-xoptions
3257
0
        config_xoptions_usage();
3258
0
        return 0;
3259
3260
0
    case '_':
3261
        // Unknown option or missing argument
3262
0
        _Py_FALLTHROUGH;
3263
0
    default:
3264
0
        config_usage(1, program);
3265
0
        return 2;
3266
0
    }
3267
0
}
3268
3269
3270
#ifdef MS_WINDOWS
3271
#  define WCSTOK wcstok_s
3272
#else
3273
0
#  define WCSTOK wcstok
3274
#endif
3275
3276
/* Get warning options from PYTHONWARNINGS environment variable. */
3277
static PyStatus
3278
config_init_env_warnoptions(PyConfig *config, PyWideStringList *warnoptions)
3279
37
{
3280
37
    PyStatus status;
3281
    /* CONFIG_GET_ENV_DUP requires dest to be initialized to NULL */
3282
37
    wchar_t *env = NULL;
3283
37
    status = CONFIG_GET_ENV_DUP(config, &env,
3284
37
                             L"PYTHONWARNINGS", "PYTHONWARNINGS");
3285
37
    if (_PyStatus_EXCEPTION(status)) {
3286
0
        return status;
3287
0
    }
3288
3289
    /* env var is not set or is empty */
3290
37
    if (env == NULL) {
3291
37
        return _PyStatus_OK();
3292
37
    }
3293
3294
3295
0
    wchar_t *warning, *context = NULL;
3296
0
    for (warning = WCSTOK(env, L",", &context);
3297
0
         warning != NULL;
3298
0
         warning = WCSTOK(NULL, L",", &context))
3299
0
    {
3300
0
        status = PyWideStringList_Append(warnoptions, warning);
3301
0
        if (_PyStatus_EXCEPTION(status)) {
3302
0
            PyMem_RawFree(env);
3303
0
            return status;
3304
0
        }
3305
0
    }
3306
0
    PyMem_RawFree(env);
3307
0
    return _PyStatus_OK();
3308
0
}
3309
3310
3311
static PyStatus
3312
warnoptions_append(PyConfig *config, PyWideStringList *options,
3313
                   const wchar_t *option)
3314
0
{
3315
    /* config_init_warnoptions() add existing config warnoptions at the end:
3316
       ensure that the new option is not already present in this list to
3317
       prevent change the options order when config_init_warnoptions() is
3318
       called twice. */
3319
0
    if (_PyWideStringList_Find(&config->warnoptions, option)) {
3320
        /* Already present: do nothing */
3321
0
        return _PyStatus_OK();
3322
0
    }
3323
0
    if (_PyWideStringList_Find(options, option)) {
3324
        /* Already present: do nothing */
3325
0
        return _PyStatus_OK();
3326
0
    }
3327
0
    return PyWideStringList_Append(options, option);
3328
0
}
3329
3330
3331
static PyStatus
3332
warnoptions_extend(PyConfig *config, PyWideStringList *options,
3333
                   const PyWideStringList *options2)
3334
111
{
3335
111
    const Py_ssize_t len = options2->length;
3336
111
    wchar_t *const *items = options2->items;
3337
3338
111
    for (Py_ssize_t i = 0; i < len; i++) {
3339
0
        PyStatus status = warnoptions_append(config, options, items[i]);
3340
0
        if (_PyStatus_EXCEPTION(status)) {
3341
0
            return status;
3342
0
        }
3343
0
    }
3344
111
    return _PyStatus_OK();
3345
111
}
3346
3347
3348
static PyStatus
3349
config_init_warnoptions(PyConfig *config,
3350
                        const PyWideStringList *cmdline_warnoptions,
3351
                        const PyWideStringList *env_warnoptions,
3352
                        const PyWideStringList *sys_warnoptions)
3353
37
{
3354
37
    PyStatus status;
3355
37
    PyWideStringList options = _PyWideStringList_INIT;
3356
3357
    /* Priority of warnings options, lowest to highest:
3358
     *
3359
     * - any implicit filters added by _warnings.c/warnings.py
3360
     * - PyConfig.dev_mode: "default" filter
3361
     * - PYTHONWARNINGS environment variable
3362
     * - '-W' command line options
3363
     * - PyConfig.bytes_warning ('-b' and '-bb' command line options):
3364
     *   "default::BytesWarning" or "error::BytesWarning" filter
3365
     * - early PySys_AddWarnOption() calls
3366
     * - PyConfig.warnoptions
3367
     *
3368
     * PyConfig.warnoptions is copied to sys.warnoptions. Since the warnings
3369
     * module works on the basis of "the most recently added filter will be
3370
     * checked first", we add the lowest precedence entries first so that later
3371
     * entries override them.
3372
     */
3373
3374
37
    if (config->dev_mode) {
3375
0
        status = warnoptions_append(config, &options, L"default");
3376
0
        if (_PyStatus_EXCEPTION(status)) {
3377
0
            goto error;
3378
0
        }
3379
0
    }
3380
3381
37
    status = warnoptions_extend(config, &options, env_warnoptions);
3382
37
    if (_PyStatus_EXCEPTION(status)) {
3383
0
        goto error;
3384
0
    }
3385
3386
37
    status = warnoptions_extend(config, &options, cmdline_warnoptions);
3387
37
    if (_PyStatus_EXCEPTION(status)) {
3388
0
        goto error;
3389
0
    }
3390
3391
    /* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c
3392
     * don't even try to emit a warning, so we skip setting the filter in that
3393
     * case.
3394
     */
3395
37
    if (config->bytes_warning) {
3396
0
        const wchar_t *filter;
3397
0
        if (config->bytes_warning> 1) {
3398
0
            filter = L"error::BytesWarning";
3399
0
        }
3400
0
        else {
3401
0
            filter = L"default::BytesWarning";
3402
0
        }
3403
0
        status = warnoptions_append(config, &options, filter);
3404
0
        if (_PyStatus_EXCEPTION(status)) {
3405
0
            goto error;
3406
0
        }
3407
0
    }
3408
3409
37
    status = warnoptions_extend(config, &options, sys_warnoptions);
3410
37
    if (_PyStatus_EXCEPTION(status)) {
3411
0
        goto error;
3412
0
    }
3413
3414
    /* Always add all PyConfig.warnoptions options */
3415
37
    status = _PyWideStringList_Extend(&options, &config->warnoptions);
3416
37
    if (_PyStatus_EXCEPTION(status)) {
3417
0
        goto error;
3418
0
    }
3419
3420
37
    _PyWideStringList_Clear(&config->warnoptions);
3421
37
    config->warnoptions = options;
3422
37
    return _PyStatus_OK();
3423
3424
0
error:
3425
0
    _PyWideStringList_Clear(&options);
3426
0
    return status;
3427
37
}
3428
3429
3430
static PyStatus
3431
config_update_argv(PyConfig *config, Py_ssize_t opt_index)
3432
0
{
3433
0
    const PyWideStringList *cmdline_argv = &config->argv;
3434
0
    PyWideStringList config_argv = _PyWideStringList_INIT;
3435
3436
    /* Copy argv to be able to modify it (to force -c/-m) */
3437
0
    if (cmdline_argv->length <= opt_index) {
3438
        /* Ensure at least one (empty) argument is seen */
3439
0
        PyStatus status = PyWideStringList_Append(&config_argv, L"");
3440
0
        if (_PyStatus_EXCEPTION(status)) {
3441
0
            return status;
3442
0
        }
3443
0
    }
3444
0
    else {
3445
0
        PyWideStringList slice;
3446
0
        slice.length = cmdline_argv->length - opt_index;
3447
0
        slice.items = &cmdline_argv->items[opt_index];
3448
0
        if (_PyWideStringList_Copy(&config_argv, &slice) < 0) {
3449
0
            return _PyStatus_NO_MEMORY();
3450
0
        }
3451
0
    }
3452
0
    assert(config_argv.length >= 1);
3453
3454
0
    wchar_t *arg0 = NULL;
3455
0
    if (config->run_command != NULL) {
3456
        /* Force sys.argv[0] = '-c' */
3457
0
        arg0 = L"-c";
3458
0
    }
3459
0
    else if (config->run_module != NULL) {
3460
        /* Force sys.argv[0] = '-m'*/
3461
0
        arg0 = L"-m";
3462
0
    }
3463
3464
0
    if (arg0 != NULL) {
3465
0
        arg0 = _PyMem_RawWcsdup(arg0);
3466
0
        if (arg0 == NULL) {
3467
0
            _PyWideStringList_Clear(&config_argv);
3468
0
            return _PyStatus_NO_MEMORY();
3469
0
        }
3470
3471
0
        PyMem_RawFree(config_argv.items[0]);
3472
0
        config_argv.items[0] = arg0;
3473
0
    }
3474
3475
0
    _PyWideStringList_Clear(&config->argv);
3476
0
    config->argv = config_argv;
3477
0
    return _PyStatus_OK();
3478
0
}
3479
3480
3481
static PyStatus
3482
core_read_precmdline(PyConfig *config, _PyPreCmdline *precmdline)
3483
37
{
3484
37
    PyStatus status;
3485
3486
37
    if (config->parse_argv == 1) {
3487
0
        if (_PyWideStringList_Copy(&precmdline->argv, &config->argv) < 0) {
3488
0
            return _PyStatus_NO_MEMORY();
3489
0
        }
3490
0
    }
3491
3492
37
    PyPreConfig preconfig;
3493
3494
37
    status = _PyPreConfig_InitFromPreConfig(&preconfig, &_PyRuntime.preconfig);
3495
37
    if (_PyStatus_EXCEPTION(status)) {
3496
0
        return status;
3497
0
    }
3498
3499
37
    _PyPreConfig_GetConfig(&preconfig, config);
3500
3501
37
    status = _PyPreCmdline_Read(precmdline, &preconfig);
3502
37
    if (_PyStatus_EXCEPTION(status)) {
3503
0
        return status;
3504
0
    }
3505
3506
37
    status = _PyPreCmdline_SetConfig(precmdline, config);
3507
37
    if (_PyStatus_EXCEPTION(status)) {
3508
0
        return status;
3509
0
    }
3510
37
    return _PyStatus_OK();
3511
37
}
3512
3513
3514
/* Get run_filename absolute path */
3515
static PyStatus
3516
config_run_filename_abspath(PyConfig *config)
3517
37
{
3518
37
    if (!config->run_filename) {
3519
37
        return _PyStatus_OK();
3520
37
    }
3521
3522
0
#ifndef MS_WINDOWS
3523
0
    if (_Py_isabs(config->run_filename)) {
3524
        /* path is already absolute */
3525
0
        return _PyStatus_OK();
3526
0
    }
3527
0
#endif
3528
3529
0
    wchar_t *abs_filename;
3530
0
    if (_Py_abspath(config->run_filename, &abs_filename) < 0) {
3531
        /* failed to get the absolute path of the command line filename:
3532
           ignore the error, keep the relative path */
3533
0
        return _PyStatus_OK();
3534
0
    }
3535
0
    if (abs_filename == NULL) {
3536
0
        return _PyStatus_NO_MEMORY();
3537
0
    }
3538
3539
0
    PyMem_RawFree(config->run_filename);
3540
0
    config->run_filename = abs_filename;
3541
0
    return _PyStatus_OK();
3542
0
}
3543
3544
3545
static PyStatus
3546
config_read_cmdline(PyConfig *config)
3547
37
{
3548
37
    PyStatus status;
3549
37
    PyWideStringList cmdline_warnoptions = _PyWideStringList_INIT;
3550
37
    PyWideStringList env_warnoptions = _PyWideStringList_INIT;
3551
37
    PyWideStringList sys_warnoptions = _PyWideStringList_INIT;
3552
3553
37
    if (config->parse_argv < 0) {
3554
0
        config->parse_argv = 1;
3555
0
    }
3556
3557
37
    if (config->parse_argv == 1) {
3558
0
        Py_ssize_t opt_index;
3559
0
        status = config_parse_cmdline(config, &cmdline_warnoptions, &opt_index);
3560
0
        if (_PyStatus_EXCEPTION(status)) {
3561
0
            goto done;
3562
0
        }
3563
3564
0
        status = config_run_filename_abspath(config);
3565
0
        if (_PyStatus_EXCEPTION(status)) {
3566
0
            goto done;
3567
0
        }
3568
3569
0
        status = config_update_argv(config, opt_index);
3570
0
        if (_PyStatus_EXCEPTION(status)) {
3571
0
            goto done;
3572
0
        }
3573
0
    }
3574
37
    else {
3575
37
        status = config_run_filename_abspath(config);
3576
37
        if (_PyStatus_EXCEPTION(status)) {
3577
0
            goto done;
3578
0
        }
3579
37
    }
3580
3581
37
    if (config->use_environment) {
3582
37
        status = config_init_env_warnoptions(config, &env_warnoptions);
3583
37
        if (_PyStatus_EXCEPTION(status)) {
3584
0
            goto done;
3585
0
        }
3586
37
    }
3587
3588
    /* Handle early PySys_AddWarnOption() calls */
3589
37
    status = _PySys_ReadPreinitWarnOptions(&sys_warnoptions);
3590
37
    if (_PyStatus_EXCEPTION(status)) {
3591
0
        goto done;
3592
0
    }
3593
3594
37
    status = config_init_warnoptions(config,
3595
37
                                     &cmdline_warnoptions,
3596
37
                                     &env_warnoptions,
3597
37
                                     &sys_warnoptions);
3598
37
    if (_PyStatus_EXCEPTION(status)) {
3599
0
        goto done;
3600
0
    }
3601
3602
37
    status = _PyStatus_OK();
3603
3604
37
done:
3605
37
    _PyWideStringList_Clear(&cmdline_warnoptions);
3606
37
    _PyWideStringList_Clear(&env_warnoptions);
3607
37
    _PyWideStringList_Clear(&sys_warnoptions);
3608
37
    return status;
3609
37
}
3610
3611
3612
PyStatus
3613
_PyConfig_SetPyArgv(PyConfig *config, const _PyArgv *args)
3614
0
{
3615
0
    PyStatus status = _Py_PreInitializeFromConfig(config, args);
3616
0
    if (_PyStatus_EXCEPTION(status)) {
3617
0
        return status;
3618
0
    }
3619
3620
0
    return _PyArgv_AsWstrList(args, &config->argv);
3621
0
}
3622
3623
3624
/* Set config.argv: decode argv using Py_DecodeLocale(). Pre-initialize Python
3625
   if needed to ensure that encodings are properly configured. */
3626
PyStatus
3627
PyConfig_SetBytesArgv(PyConfig *config, Py_ssize_t argc, char * const *argv)
3628
0
{
3629
0
    _PyArgv args = {
3630
0
        .argc = argc,
3631
0
        .use_bytes_argv = 1,
3632
0
        .bytes_argv = argv,
3633
0
        .wchar_argv = NULL};
3634
0
    return _PyConfig_SetPyArgv(config, &args);
3635
0
}
3636
3637
3638
PyStatus
3639
PyConfig_SetArgv(PyConfig *config, Py_ssize_t argc, wchar_t * const *argv)
3640
0
{
3641
0
    _PyArgv args = {
3642
0
        .argc = argc,
3643
0
        .use_bytes_argv = 0,
3644
0
        .bytes_argv = NULL,
3645
0
        .wchar_argv = argv};
3646
0
    return _PyConfig_SetPyArgv(config, &args);
3647
0
}
3648
3649
3650
PyStatus
3651
PyConfig_SetWideStringList(PyConfig *config, PyWideStringList *list,
3652
                           Py_ssize_t length, wchar_t **items)
3653
0
{
3654
0
    PyStatus status = _Py_PreInitializeFromConfig(config, NULL);
3655
0
    if (_PyStatus_EXCEPTION(status)) {
3656
0
        return status;
3657
0
    }
3658
3659
0
    PyWideStringList list2 = {.length = length, .items = items};
3660
0
    if (_PyWideStringList_Copy(list, &list2) < 0) {
3661
0
        return _PyStatus_NO_MEMORY();
3662
0
    }
3663
0
    return _PyStatus_OK();
3664
0
}
3665
3666
3667
#ifdef __CYGWIN__
3668
// Cygwin strips ".exe" suffix from argv[0].
3669
// Add again the ".exe" suffix.
3670
static PyStatus
3671
config_argv0_add_exe(PyConfig *config)
3672
{
3673
    if (config->argv.length < 1) {
3674
        return _PyStatus_OK();
3675
    }
3676
    const wchar_t *argv0 = config->argv.items[0];
3677
    size_t len = wcslen(argv0);
3678
    if (len >= 5 && wcscmp(argv0 + len - 4, L".exe") == 0) {
3679
        return _PyStatus_OK();
3680
    }
3681
3682
    wchar_t *exe = PyMem_RawMalloc((len + 4 + 1) * sizeof(wchar_t));
3683
    if (exe == NULL) {
3684
        return _PyStatus_NO_MEMORY();
3685
    }
3686
    wcscpy(exe, argv0);
3687
    wcscat(exe, L".exe");
3688
3689
    FILE *fp = _Py_wfopen(exe, L"rb");
3690
    if (fp != NULL) {
3691
        fclose(fp);
3692
3693
        PyMem_RawFree(config->argv.items[0]);
3694
        config->argv.items[0] = exe;
3695
    }
3696
    else {
3697
        PyMem_RawFree(exe);
3698
    }
3699
3700
    return _PyStatus_OK();
3701
}
3702
#endif
3703
3704
3705
/* Read the configuration into PyConfig from:
3706
3707
   * Command line arguments
3708
   * Environment variables
3709
3710
   The only side effects are to modify config and to call _Py_SetArgcArgv(). */
3711
PyStatus
3712
_PyConfig_Read(PyConfig *config, int compute_path_config)
3713
37
{
3714
37
    PyStatus status;
3715
3716
37
    status = _Py_PreInitializeFromConfig(config, NULL);
3717
37
    if (_PyStatus_EXCEPTION(status)) {
3718
0
        return status;
3719
0
    }
3720
3721
37
    config_read_preconfig(config);
3722
3723
    // Set default values
3724
37
    if (config->bytes_warning < 0) {
3725
37
        config->bytes_warning = 0;
3726
37
    }
3727
37
    if (config->inspect < 0) {
3728
37
        config->inspect = 0;
3729
37
    }
3730
37
    if (config->interactive < 0) {
3731
37
        config->interactive = 0;
3732
37
    }
3733
37
    if (config->optimization_level < 0) {
3734
37
        config->optimization_level = 0;
3735
37
    }
3736
37
    if (config->parser_debug < 0) {
3737
37
        config->parser_debug = 0;
3738
37
    }
3739
37
    if (config->quiet < 0) {
3740
37
        config->quiet = 0;
3741
37
    }
3742
37
    if (config->use_environment < 0) {
3743
0
        config->use_environment = 0;
3744
0
    }
3745
37
    if (config->verbose < 0) {
3746
37
        config->verbose = 0;
3747
37
    }
3748
37
    if (config->write_bytecode < 0) {
3749
37
        config->write_bytecode = 1;
3750
37
    }
3751
37
    if (config->buffered_stdio < 0) {
3752
37
        config->buffered_stdio = 1;
3753
37
    }
3754
37
    if (config->isolated < 0) {
3755
0
        config->isolated = 0;
3756
0
    }
3757
#ifdef MS_WINDOWS
3758
    if (config->legacy_windows_stdio < 0) {
3759
        config->legacy_windows_stdio = 0;
3760
    }
3761
#endif
3762
37
    if (config->pathconfig_warnings < 0) {
3763
37
        config->pathconfig_warnings = 1;
3764
37
    }
3765
37
    if (config->site_import < 0) {
3766
37
        config->site_import = 1;
3767
37
    }
3768
37
    if (config->user_site_directory < 0) {
3769
37
        config->user_site_directory = 1;
3770
37
    }
3771
3772
#ifdef __CYGWIN__
3773
    status = config_argv0_add_exe(config);
3774
    if (_PyStatus_EXCEPTION(status)) {
3775
        return status;
3776
    }
3777
#endif
3778
3779
37
    if (config->orig_argv.length == 0
3780
37
        && !(config->argv.length == 1
3781
0
             && wcscmp(config->argv.items[0], L"") == 0))
3782
37
    {
3783
37
        if (_PyWideStringList_Copy(&config->orig_argv, &config->argv) < 0) {
3784
0
            return _PyStatus_NO_MEMORY();
3785
0
        }
3786
37
    }
3787
3788
37
    _PyPreCmdline precmdline = _PyPreCmdline_INIT;
3789
37
    status = core_read_precmdline(config, &precmdline);
3790
37
    if (_PyStatus_EXCEPTION(status)) {
3791
0
        goto done;
3792
0
    }
3793
3794
37
    assert(config->isolated >= 0);
3795
37
    if (config->isolated) {
3796
0
        config->safe_path = 1;
3797
0
        config->use_environment = 0;
3798
0
        config->user_site_directory = 0;
3799
0
    }
3800
3801
37
    status = config_read_cmdline(config);
3802
37
    if (_PyStatus_EXCEPTION(status)) {
3803
0
        goto done;
3804
0
    }
3805
3806
    /* Handle early PySys_AddXOption() calls */
3807
37
    status = _PySys_ReadPreinitXOptions(config);
3808
37
    if (_PyStatus_EXCEPTION(status)) {
3809
0
        goto done;
3810
0
    }
3811
3812
37
    status = config_read(config, compute_path_config);
3813
37
    if (_PyStatus_EXCEPTION(status)) {
3814
0
        goto done;
3815
0
    }
3816
3817
37
    assert(config_check_consistency(config));
3818
3819
37
    status = _PyStatus_OK();
3820
3821
37
done:
3822
37
    _PyPreCmdline_Clear(&precmdline);
3823
37
    return status;
3824
37
}
3825
3826
3827
PyStatus
3828
PyConfig_Read(PyConfig *config)
3829
0
{
3830
0
    return _PyConfig_Read(config, 0);
3831
0
}
3832
3833
3834
PyObject*
3835
_Py_GetConfigsAsDict(void)
3836
0
{
3837
0
    PyObject *result = NULL;
3838
0
    PyObject *dict = NULL;
3839
3840
0
    result = PyDict_New();
3841
0
    if (result == NULL) {
3842
0
        goto error;
3843
0
    }
3844
3845
    /* global result */
3846
0
    dict = _Py_GetGlobalVariablesAsDict();
3847
0
    if (dict == NULL) {
3848
0
        goto error;
3849
0
    }
3850
0
    if (PyDict_SetItemString(result, "global_config", dict) < 0) {
3851
0
        goto error;
3852
0
    }
3853
0
    Py_CLEAR(dict);
3854
3855
    /* pre config */
3856
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
3857
0
    const PyPreConfig *pre_config = &interp->runtime->preconfig;
3858
0
    dict = _PyPreConfig_AsDict(pre_config);
3859
0
    if (dict == NULL) {
3860
0
        goto error;
3861
0
    }
3862
0
    if (PyDict_SetItemString(result, "pre_config", dict) < 0) {
3863
0
        goto error;
3864
0
    }
3865
0
    Py_CLEAR(dict);
3866
3867
    /* core config */
3868
0
    const PyConfig *config = _PyInterpreterState_GetConfig(interp);
3869
0
    dict = _PyConfig_AsDict(config);
3870
0
    if (dict == NULL) {
3871
0
        goto error;
3872
0
    }
3873
0
    if (PyDict_SetItemString(result, "config", dict) < 0) {
3874
0
        goto error;
3875
0
    }
3876
0
    Py_CLEAR(dict);
3877
3878
0
    return result;
3879
3880
0
error:
3881
0
    Py_XDECREF(result);
3882
0
    Py_XDECREF(dict);
3883
0
    return NULL;
3884
0
}
3885
3886
3887
static void
3888
init_dump_ascii_wstr(const wchar_t *str)
3889
0
{
3890
0
    if (str == NULL) {
3891
0
        PySys_WriteStderr("(not set)");
3892
0
        return;
3893
0
    }
3894
3895
0
    PySys_WriteStderr("'");
3896
0
    for (; *str != L'\0'; str++) {
3897
0
        unsigned int ch = (unsigned int)*str;
3898
0
        if (ch == L'\'') {
3899
0
            PySys_WriteStderr("\\'");
3900
0
        } else if (0x20 <= ch && ch < 0x7f) {
3901
0
            PySys_WriteStderr("%c", ch);
3902
0
        }
3903
0
        else if (ch <= 0xff) {
3904
0
            PySys_WriteStderr("\\x%02x", ch);
3905
0
        }
3906
0
#if SIZEOF_WCHAR_T > 2
3907
0
        else if (ch > 0xffff) {
3908
0
            PySys_WriteStderr("\\U%08x", ch);
3909
0
        }
3910
0
#endif
3911
0
        else {
3912
0
            PySys_WriteStderr("\\u%04x", ch);
3913
0
        }
3914
0
    }
3915
0
    PySys_WriteStderr("'");
3916
0
}
3917
3918
3919
/* Dump the Python path configuration into sys.stderr */
3920
void
3921
_Py_DumpPathConfig(PyThreadState *tstate)
3922
0
{
3923
0
    PyObject *exc = _PyErr_GetRaisedException(tstate);
3924
3925
0
    PySys_WriteStderr("Python path configuration:\n");
3926
3927
0
#define DUMP_CONFIG(NAME, FIELD) \
3928
0
        do { \
3929
0
            PySys_WriteStderr("  " NAME " = "); \
3930
0
            init_dump_ascii_wstr(config->FIELD); \
3931
0
            PySys_WriteStderr("\n"); \
3932
0
        } while (0)
3933
3934
0
    const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
3935
0
    DUMP_CONFIG("PYTHONHOME", home);
3936
0
    DUMP_CONFIG("PYTHONPATH", pythonpath_env);
3937
0
    DUMP_CONFIG("program name", program_name);
3938
0
    PySys_WriteStderr("  isolated = %i\n", config->isolated);
3939
0
    PySys_WriteStderr("  environment = %i\n", config->use_environment);
3940
0
    PySys_WriteStderr("  user site = %i\n", config->user_site_directory);
3941
0
    PySys_WriteStderr("  safe_path = %i\n", config->safe_path);
3942
0
    PySys_WriteStderr("  import site = %i\n", config->site_import);
3943
0
    PySys_WriteStderr("  is in build tree = %i\n", config->_is_python_build);
3944
0
    DUMP_CONFIG("stdlib dir", stdlib_dir);
3945
0
    DUMP_CONFIG("sys.path[0]", sys_path_0);
3946
0
#undef DUMP_CONFIG
3947
3948
0
#define DUMP_SYS(NAME) \
3949
0
        do { \
3950
0
            PySys_FormatStderr("  sys.%s = ", #NAME); \
3951
0
            if (PySys_GetOptionalAttrString(#NAME, &obj) < 0) { \
3952
0
                PyErr_Clear(); \
3953
0
            } \
3954
0
            if (obj != NULL) { \
3955
0
                PySys_FormatStderr("%A", obj); \
3956
0
                Py_DECREF(obj); \
3957
0
            } \
3958
0
            else { \
3959
0
                PySys_WriteStderr("(not set)"); \
3960
0
            } \
3961
0
            PySys_FormatStderr("\n"); \
3962
0
        } while (0)
3963
3964
0
    PyObject *obj;
3965
0
    DUMP_SYS(_base_executable);
3966
0
    DUMP_SYS(base_prefix);
3967
0
    DUMP_SYS(base_exec_prefix);
3968
0
    DUMP_SYS(platlibdir);
3969
0
    DUMP_SYS(executable);
3970
0
    DUMP_SYS(prefix);
3971
0
    DUMP_SYS(exec_prefix);
3972
0
#undef DUMP_SYS
3973
3974
0
    PyObject *sys_path;
3975
0
    (void) PySys_GetOptionalAttrString("path", &sys_path);
3976
0
    if (sys_path != NULL && PyList_Check(sys_path)) {
3977
0
        PySys_WriteStderr("  sys.path = [\n");
3978
0
        Py_ssize_t len = PyList_GET_SIZE(sys_path);
3979
0
        for (Py_ssize_t i=0; i < len; i++) {
3980
0
            PyObject *path = PyList_GET_ITEM(sys_path, i);
3981
0
            PySys_FormatStderr("    %A,\n", path);
3982
0
        }
3983
0
        PySys_WriteStderr("  ]\n");
3984
0
    }
3985
0
    Py_XDECREF(sys_path);
3986
3987
0
    _PyErr_SetRaisedException(tstate, exc);
3988
0
}
3989
3990
3991
// --- PyInitConfig API ---------------------------------------------------
3992
3993
struct PyInitConfig {
3994
    PyPreConfig preconfig;
3995
    PyConfig config;
3996
    struct _inittab *inittab;
3997
    Py_ssize_t inittab_size;
3998
    PyStatus status;
3999
    char *err_msg;
4000
};
4001
4002
static PyInitConfig*
4003
initconfig_alloc(void)
4004
0
{
4005
0
    return calloc(1, sizeof(PyInitConfig));
4006
0
}
4007
4008
4009
PyInitConfig*
4010
PyInitConfig_Create(void)
4011
0
{
4012
0
    PyInitConfig *config = initconfig_alloc();
4013
0
    if (config == NULL) {
4014
0
        return NULL;
4015
0
    }
4016
0
    PyPreConfig_InitIsolatedConfig(&config->preconfig);
4017
0
    PyConfig_InitIsolatedConfig(&config->config);
4018
0
    config->status = _PyStatus_OK();
4019
0
    return config;
4020
0
}
4021
4022
4023
void
4024
PyInitConfig_Free(PyInitConfig *config)
4025
0
{
4026
0
    if (config == NULL) {
4027
0
        return;
4028
0
    }
4029
4030
0
    initconfig_free_config(&config->config);
4031
0
    PyMem_RawFree(config->inittab);
4032
0
    free(config->err_msg);
4033
0
    free(config);
4034
0
}
4035
4036
4037
int
4038
PyInitConfig_GetError(PyInitConfig* config, const char **perr_msg)
4039
0
{
4040
0
    assert(!_PyStatus_IS_EXIT(config->status));
4041
4042
0
    if (_PyStatus_IS_ERROR(config->status) && config->status.err_msg != NULL) {
4043
0
        *perr_msg = config->status.err_msg;
4044
0
        return 1;
4045
0
    }
4046
0
    else {
4047
0
        *perr_msg = NULL;
4048
0
        return 0;
4049
0
    }
4050
0
}
4051
4052
4053
int
4054
PyInitConfig_GetExitCode(PyInitConfig* config, int *exitcode)
4055
0
{
4056
0
    assert(!_PyStatus_IS_EXIT(config->status));
4057
0
    return 0;
4058
0
}
4059
4060
4061
static void
4062
initconfig_set_error(PyInitConfig *config, const char *err_msg)
4063
0
{
4064
0
    config->status = _PyStatus_ERR(err_msg);
4065
0
}
4066
4067
4068
static const PyConfigSpec*
4069
initconfig_find_spec(const PyConfigSpec *spec, const char *name)
4070
0
{
4071
0
    for (; spec->name != NULL; spec++) {
4072
0
        if (strcmp(name, spec->name) == 0) {
4073
0
            return spec;
4074
0
        }
4075
0
    }
4076
0
    return NULL;
4077
0
}
4078
4079
4080
int
4081
PyInitConfig_HasOption(PyInitConfig *config, const char *name)
4082
0
{
4083
0
    const PyConfigSpec *spec = initconfig_find_spec(PYCONFIG_SPEC, name);
4084
0
    if (spec == NULL) {
4085
0
        spec = initconfig_find_spec(PYPRECONFIG_SPEC, name);
4086
0
    }
4087
0
    return (spec != NULL);
4088
0
}
4089
4090
4091
static const PyConfigSpec*
4092
initconfig_prepare(PyInitConfig *config, const char *name, void **raw_member)
4093
0
{
4094
0
    const PyConfigSpec *spec = initconfig_find_spec(PYCONFIG_SPEC, name);
4095
0
    if (spec != NULL) {
4096
0
        *raw_member = config_get_spec_member(&config->config, spec);
4097
0
        return spec;
4098
0
    }
4099
4100
0
    spec = initconfig_find_spec(PYPRECONFIG_SPEC, name);
4101
0
    if (spec != NULL) {
4102
0
        *raw_member = preconfig_get_spec_member(&config->preconfig, spec);
4103
0
        return spec;
4104
0
    }
4105
4106
0
    initconfig_set_error(config, "unknown config option name");
4107
0
    return NULL;
4108
0
}
4109
4110
4111
int
4112
PyInitConfig_GetInt(PyInitConfig *config, const char *name, int64_t *value)
4113
0
{
4114
0
    void *raw_member;
4115
0
    const PyConfigSpec *spec = initconfig_prepare(config, name, &raw_member);
4116
0
    if (spec == NULL) {
4117
0
        return -1;
4118
0
    }
4119
4120
0
    switch (spec->type) {
4121
0
    case PyConfig_MEMBER_INT:
4122
0
    case PyConfig_MEMBER_UINT:
4123
0
    case PyConfig_MEMBER_BOOL:
4124
0
    {
4125
0
        int *member = raw_member;
4126
0
        *value = *member;
4127
0
        break;
4128
0
    }
4129
4130
0
    case PyConfig_MEMBER_ULONG:
4131
0
    {
4132
0
        unsigned long *member = raw_member;
4133
0
#if SIZEOF_LONG >= 8
4134
0
        if ((unsigned long)INT64_MAX < *member) {
4135
0
            initconfig_set_error(config,
4136
0
                "config option value doesn't fit into int64_t");
4137
0
            return -1;
4138
0
        }
4139
0
#endif
4140
0
        *value = *member;
4141
0
        break;
4142
0
    }
4143
4144
0
    default:
4145
0
        initconfig_set_error(config, "config option type is not int");
4146
0
        return -1;
4147
0
    }
4148
0
    return 0;
4149
0
}
4150
4151
4152
static char*
4153
wstr_to_utf8(PyInitConfig *config, wchar_t *wstr)
4154
0
{
4155
0
    char *utf8;
4156
0
    size_t utf8_len;
4157
0
    int res = _Py_EncodeUTF8(wstr, &utf8, &utf8_len,
4158
0
                             NULL, 1, _Py_ERROR_STRICT);
4159
0
    if (res == -2) {
4160
0
        initconfig_set_error(config, "encoding error");
4161
0
        return NULL;
4162
0
    }
4163
0
    if (res < 0) {
4164
0
        config->status = _PyStatus_NO_MEMORY();
4165
0
        return NULL;
4166
0
    }
4167
4168
    // Copy to use the malloc() memory allocator
4169
0
    size_t size = utf8_len + 1;
4170
0
    char *str = malloc(size);
4171
0
    if (str == NULL) {
4172
0
        PyMem_RawFree(utf8);
4173
0
        config->status = _PyStatus_NO_MEMORY();
4174
0
        return NULL;
4175
0
    }
4176
4177
0
    memcpy(str, utf8, size);
4178
0
    PyMem_RawFree(utf8);
4179
0
    return str;
4180
0
}
4181
4182
4183
int
4184
PyInitConfig_GetStr(PyInitConfig *config, const char *name, char **value)
4185
0
{
4186
0
    void *raw_member;
4187
0
    const PyConfigSpec *spec = initconfig_prepare(config, name, &raw_member);
4188
0
    if (spec == NULL) {
4189
0
        return -1;
4190
0
    }
4191
4192
0
    if (spec->type != PyConfig_MEMBER_WSTR
4193
0
        && spec->type != PyConfig_MEMBER_WSTR_OPT)
4194
0
    {
4195
0
        initconfig_set_error(config, "config option type is not string");
4196
0
        return -1;
4197
0
    }
4198
4199
0
    wchar_t **member = raw_member;
4200
0
    if (*member == NULL) {
4201
0
        *value = NULL;
4202
0
        return 0;
4203
0
    }
4204
4205
0
    *value = wstr_to_utf8(config, *member);
4206
0
    if (*value == NULL) {
4207
0
        return -1;
4208
0
    }
4209
0
    return 0;
4210
0
}
4211
4212
4213
int
4214
PyInitConfig_GetStrList(PyInitConfig *config, const char *name, size_t *length, char ***items)
4215
0
{
4216
0
    void *raw_member;
4217
0
    const PyConfigSpec *spec = initconfig_prepare(config, name, &raw_member);
4218
0
    if (spec == NULL) {
4219
0
        return -1;
4220
0
    }
4221
4222
0
    if (spec->type != PyConfig_MEMBER_WSTR_LIST) {
4223
0
        initconfig_set_error(config, "config option type is not string list");
4224
0
        return -1;
4225
0
    }
4226
4227
0
    PyWideStringList *list = raw_member;
4228
0
    *length = list->length;
4229
4230
0
    *items = malloc(list->length * sizeof(char*));
4231
0
    if (*items == NULL) {
4232
0
        config->status = _PyStatus_NO_MEMORY();
4233
0
        return -1;
4234
0
    }
4235
4236
0
    for (Py_ssize_t i=0; i < list->length; i++) {
4237
0
        (*items)[i] = wstr_to_utf8(config, list->items[i]);
4238
0
        if ((*items)[i] == NULL) {
4239
0
            PyInitConfig_FreeStrList(i, *items);
4240
0
            return -1;
4241
0
        }
4242
0
    }
4243
0
    return 0;
4244
0
}
4245
4246
4247
void
4248
PyInitConfig_FreeStrList(size_t length, char **items)
4249
0
{
4250
0
    for (size_t i=0; i < length; i++) {
4251
0
        free(items[i]);
4252
0
    }
4253
0
    free(items);
4254
0
}
4255
4256
4257
int
4258
PyInitConfig_SetInt(PyInitConfig *config, const char *name, int64_t value)
4259
0
{
4260
0
    void *raw_member;
4261
0
    const PyConfigSpec *spec = initconfig_prepare(config, name, &raw_member);
4262
0
    if (spec == NULL) {
4263
0
        return -1;
4264
0
    }
4265
4266
0
    switch (spec->type) {
4267
0
    case PyConfig_MEMBER_INT:
4268
0
    {
4269
0
        if (value < (int64_t)INT_MIN || (int64_t)INT_MAX < value) {
4270
0
            initconfig_set_error(config,
4271
0
                "config option value is out of int range");
4272
0
            return -1;
4273
0
        }
4274
0
        int int_value = (int)value;
4275
4276
0
        int *member = raw_member;
4277
0
        *member = int_value;
4278
0
        break;
4279
0
    }
4280
4281
0
    case PyConfig_MEMBER_UINT:
4282
0
    case PyConfig_MEMBER_BOOL:
4283
0
    {
4284
0
        if (value < 0 || (uint64_t)UINT_MAX < (uint64_t)value) {
4285
0
            initconfig_set_error(config,
4286
0
                "config option value is out of unsigned int range");
4287
0
            return -1;
4288
0
        }
4289
0
        int int_value = (int)value;
4290
4291
0
        int *member = raw_member;
4292
0
        *member = int_value;
4293
0
        break;
4294
0
    }
4295
4296
0
    case PyConfig_MEMBER_ULONG:
4297
0
    {
4298
0
        if (value < 0 || (uint64_t)ULONG_MAX < (uint64_t)value) {
4299
0
            initconfig_set_error(config,
4300
0
                "config option value is out of unsigned long range");
4301
0
            return -1;
4302
0
        }
4303
0
        unsigned long ulong_value = (unsigned long)value;
4304
4305
0
        unsigned long *member = raw_member;
4306
0
        *member = ulong_value;
4307
0
        break;
4308
0
    }
4309
4310
0
    default:
4311
0
        initconfig_set_error(config, "config option type is not int");
4312
0
        return -1;
4313
0
    }
4314
4315
0
    if (strcmp(name, "hash_seed") == 0) {
4316
0
        config->config.use_hash_seed = 1;
4317
0
    }
4318
4319
0
    return 0;
4320
0
}
4321
4322
4323
static wchar_t*
4324
utf8_to_wstr(PyInitConfig *config, const char *str)
4325
0
{
4326
0
    wchar_t *wstr;
4327
0
    size_t wlen;
4328
0
    int res = _Py_DecodeUTF8(str, strlen(str), &wstr, &wlen, _Py_ERROR_STRICT);
4329
0
    if (res == _Py_CODEC_DECODE_ERROR) {
4330
0
        initconfig_set_error(config, "decoding error");
4331
0
        return NULL;
4332
0
    }
4333
0
    if (res < 0) {
4334
0
        assert(res == _Py_CODEC_MEMORY_ERROR);
4335
0
        config->status = _PyStatus_NO_MEMORY();
4336
0
        return NULL;
4337
0
    }
4338
4339
    // Copy to use the malloc() memory allocator
4340
0
    size_t size = (wlen + 1) * sizeof(wchar_t);
4341
0
    wchar_t *wstr2 = malloc(size);
4342
0
    if (wstr2 == NULL) {
4343
0
        PyMem_RawFree(wstr);
4344
0
        config->status = _PyStatus_NO_MEMORY();
4345
0
        return NULL;
4346
0
    }
4347
4348
0
    memcpy(wstr2, wstr, size);
4349
0
    PyMem_RawFree(wstr);
4350
0
    return wstr2;
4351
0
}
4352
4353
4354
int
4355
PyInitConfig_SetStr(PyInitConfig *config, const char *name, const char* value)
4356
0
{
4357
0
    void *raw_member;
4358
0
    const PyConfigSpec *spec = initconfig_prepare(config, name, &raw_member);
4359
0
    if (spec == NULL) {
4360
0
        return -1;
4361
0
    }
4362
4363
0
    if (spec->type != PyConfig_MEMBER_WSTR
4364
0
            && spec->type != PyConfig_MEMBER_WSTR_OPT) {
4365
0
        initconfig_set_error(config, "config option type is not string");
4366
0
        return -1;
4367
0
    }
4368
4369
0
    if (value == NULL && spec->type != PyConfig_MEMBER_WSTR_OPT) {
4370
0
        initconfig_set_error(config, "config option string cannot be NULL");
4371
0
    }
4372
4373
0
    wchar_t **member = raw_member;
4374
4375
0
    *member = utf8_to_wstr(config, value);
4376
0
    if (*member == NULL) {
4377
0
        return -1;
4378
0
    }
4379
0
    return 0;
4380
0
}
4381
4382
4383
static void
4384
initconfig_free_wstr(wchar_t *member)
4385
0
{
4386
0
    if (member) {
4387
0
        free(member);
4388
0
    }
4389
0
}
4390
4391
4392
static void
4393
initconfig_free_wstr_list(PyWideStringList *list)
4394
0
{
4395
0
    for (Py_ssize_t i = 0; i < list->length; i++) {
4396
0
        free(list->items[i]);
4397
0
    }
4398
0
    free(list->items);
4399
0
}
4400
4401
4402
static void
4403
initconfig_free_config(const PyConfig *config)
4404
0
{
4405
0
    const PyConfigSpec *spec = PYCONFIG_SPEC;
4406
0
    for (; spec->name != NULL; spec++) {
4407
0
        void *member = config_get_spec_member(config, spec);
4408
0
        if (spec->type == PyConfig_MEMBER_WSTR
4409
0
            || spec->type == PyConfig_MEMBER_WSTR_OPT)
4410
0
        {
4411
0
            wchar_t *wstr = *(wchar_t **)member;
4412
0
            initconfig_free_wstr(wstr);
4413
0
        }
4414
0
        else if (spec->type == PyConfig_MEMBER_WSTR_LIST) {
4415
0
            initconfig_free_wstr_list(member);
4416
0
        }
4417
0
    }
4418
0
}
4419
4420
4421
static int
4422
initconfig_set_str_list(PyInitConfig *config, PyWideStringList *list,
4423
                        Py_ssize_t length, char * const *items)
4424
0
{
4425
0
    PyWideStringList wlist = _PyWideStringList_INIT;
4426
0
    size_t size = sizeof(wchar_t*) * length;
4427
0
    wlist.items = (wchar_t **)malloc(size);
4428
0
    if (wlist.items == NULL) {
4429
0
        config->status = _PyStatus_NO_MEMORY();
4430
0
        return -1;
4431
0
    }
4432
4433
0
    for (Py_ssize_t i = 0; i < length; i++) {
4434
0
        wchar_t *arg = utf8_to_wstr(config, items[i]);
4435
0
        if (arg == NULL) {
4436
0
            initconfig_free_wstr_list(&wlist);
4437
0
            return -1;
4438
0
        }
4439
0
        wlist.items[i] = arg;
4440
0
        wlist.length++;
4441
0
    }
4442
4443
0
    initconfig_free_wstr_list(list);
4444
0
    *list = wlist;
4445
0
    return 0;
4446
0
}
4447
4448
4449
int
4450
PyInitConfig_SetStrList(PyInitConfig *config, const char *name,
4451
                        size_t length, char * const *items)
4452
0
{
4453
0
    void *raw_member;
4454
0
    const PyConfigSpec *spec = initconfig_prepare(config, name, &raw_member);
4455
0
    if (spec == NULL) {
4456
0
        return -1;
4457
0
    }
4458
4459
0
    if (spec->type != PyConfig_MEMBER_WSTR_LIST) {
4460
0
        initconfig_set_error(config, "config option type is not strings list");
4461
0
        return -1;
4462
0
    }
4463
0
    PyWideStringList *list = raw_member;
4464
0
    if (initconfig_set_str_list(config, list, length, items) < 0) {
4465
0
        return -1;
4466
0
    }
4467
4468
0
    if (strcmp(name, "module_search_paths") == 0) {
4469
0
        config->config.module_search_paths_set = 1;
4470
0
    }
4471
0
    return 0;
4472
0
}
4473
4474
4475
int
4476
PyInitConfig_AddModule(PyInitConfig *config, const char *name,
4477
                       PyObject* (*initfunc)(void))
4478
0
{
4479
0
    size_t size = sizeof(struct _inittab) * (config->inittab_size + 2);
4480
0
    struct _inittab *new_inittab = PyMem_RawRealloc(config->inittab, size);
4481
0
    if (new_inittab == NULL) {
4482
0
        config->status = _PyStatus_NO_MEMORY();
4483
0
        return -1;
4484
0
    }
4485
0
    config->inittab = new_inittab;
4486
4487
0
    struct _inittab *entry = &config->inittab[config->inittab_size];
4488
0
    entry->name = name;
4489
0
    entry->initfunc = initfunc;
4490
4491
    // Terminator entry
4492
0
    entry = &config->inittab[config->inittab_size + 1];
4493
0
    entry->name = NULL;
4494
0
    entry->initfunc = NULL;
4495
4496
0
    config->inittab_size++;
4497
0
    return 0;
4498
0
}
4499
4500
4501
int
4502
Py_InitializeFromInitConfig(PyInitConfig *config)
4503
0
{
4504
0
    if (config->inittab_size >= 1) {
4505
0
        if (PyImport_ExtendInittab(config->inittab) < 0) {
4506
0
            config->status = _PyStatus_NO_MEMORY();
4507
0
            return -1;
4508
0
        }
4509
0
    }
4510
4511
0
    _PyPreConfig_GetConfig(&config->preconfig, &config->config);
4512
4513
0
    config->status = Py_PreInitializeFromArgs(
4514
0
        &config->preconfig,
4515
0
        config->config.argv.length,
4516
0
        config->config.argv.items);
4517
0
    if (_PyStatus_EXCEPTION(config->status)) {
4518
0
        return -1;
4519
0
    }
4520
4521
0
    config->status = Py_InitializeFromConfig(&config->config);
4522
0
    if (_PyStatus_EXCEPTION(config->status)) {
4523
0
        return -1;
4524
0
    }
4525
4526
0
    return 0;
4527
0
}
4528
4529
4530
// --- PyConfig_Get() -------------------------------------------------------
4531
4532
static const PyConfigSpec*
4533
config_generic_find_spec(const PyConfigSpec *spec, const char *name)
4534
0
{
4535
0
    for (; spec->name != NULL; spec++) {
4536
0
        if (spec->visibility == PyConfig_MEMBER_INIT_ONLY) {
4537
0
            continue;
4538
0
        }
4539
0
        if (strcmp(name, spec->name) == 0) {
4540
0
            return spec;
4541
0
        }
4542
0
    }
4543
0
    return NULL;
4544
0
}
4545
4546
4547
static const PyConfigSpec*
4548
config_find_spec(const char *name)
4549
0
{
4550
0
    return config_generic_find_spec(PYCONFIG_SPEC, name);
4551
0
}
4552
4553
4554
static const PyConfigSpec*
4555
preconfig_find_spec(const char *name)
4556
0
{
4557
0
    return config_generic_find_spec(PYPRECONFIG_SPEC, name);
4558
0
}
4559
4560
4561
static int
4562
config_add_xoption(PyObject *dict, const wchar_t *str)
4563
0
{
4564
0
    PyObject *name = NULL, *value = NULL;
4565
4566
0
    const wchar_t *name_end = wcschr(str, L'=');
4567
0
    if (!name_end) {
4568
0
        name = PyUnicode_FromWideChar(str, -1);
4569
0
        if (name == NULL) {
4570
0
            goto error;
4571
0
        }
4572
0
        value = Py_NewRef(Py_True);
4573
0
    }
4574
0
    else {
4575
0
        name = PyUnicode_FromWideChar(str, name_end - str);
4576
0
        if (name == NULL) {
4577
0
            goto error;
4578
0
        }
4579
0
        value = PyUnicode_FromWideChar(name_end + 1, -1);
4580
0
        if (value == NULL) {
4581
0
            goto error;
4582
0
        }
4583
0
    }
4584
0
    if (PyDict_SetItem(dict, name, value) < 0) {
4585
0
        goto error;
4586
0
    }
4587
0
    Py_DECREF(name);
4588
0
    Py_DECREF(value);
4589
0
    return 0;
4590
4591
0
error:
4592
0
    Py_XDECREF(name);
4593
0
    Py_XDECREF(value);
4594
0
    return -1;
4595
0
}
4596
4597
4598
PyObject*
4599
_PyConfig_CreateXOptionsDict(const PyConfig *config)
4600
74
{
4601
74
    PyObject *dict = PyDict_New();
4602
74
    if (dict == NULL) {
4603
0
        return NULL;
4604
0
    }
4605
4606
74
    Py_ssize_t nxoption = config->xoptions.length;
4607
74
    wchar_t **xoptions = config->xoptions.items;
4608
74
    for (Py_ssize_t i=0; i < nxoption; i++) {
4609
0
        const wchar_t *option = xoptions[i];
4610
0
        if (config_add_xoption(dict, option) < 0) {
4611
0
            Py_DECREF(dict);
4612
0
            return NULL;
4613
0
        }
4614
0
    }
4615
74
    return dict;
4616
74
}
4617
4618
4619
static int
4620
config_get_sys_write_bytecode(const PyConfig *config, int *value)
4621
0
{
4622
0
    PyObject *attr = PySys_GetAttrString("dont_write_bytecode");
4623
0
    if (attr == NULL) {
4624
0
        return -1;
4625
0
    }
4626
4627
0
    int is_true = PyObject_IsTrue(attr);
4628
0
    Py_DECREF(attr);
4629
0
    if (is_true < 0) {
4630
0
        return -1;
4631
0
    }
4632
0
    *value = (!is_true);
4633
0
    return 0;
4634
0
}
4635
4636
4637
static PyObject*
4638
config_get(const PyConfig *config, const PyConfigSpec *spec,
4639
           int use_sys)
4640
2.66k
{
4641
2.66k
    if (use_sys) {
4642
0
        if (spec->sys.attr != NULL) {
4643
0
            return PySys_GetAttrString(spec->sys.attr);
4644
0
        }
4645
4646
0
        if (strcmp(spec->name, "write_bytecode") == 0) {
4647
0
            int value;
4648
0
            if (config_get_sys_write_bytecode(config, &value) < 0) {
4649
0
                return NULL;
4650
0
            }
4651
0
            return PyBool_FromLong(value);
4652
0
        }
4653
4654
0
        if (strcmp(spec->name, "int_max_str_digits") == 0) {
4655
0
            PyInterpreterState *interp = _PyInterpreterState_GET();
4656
0
            int maxdigits = _Py_atomic_load_int(&interp->long_state.max_str_digits);
4657
0
            return PyLong_FromLong(maxdigits);
4658
0
        }
4659
0
    }
4660
4661
2.66k
    void *member = config_get_spec_member(config, spec);
4662
2.66k
    switch (spec->type) {
4663
185
    case PyConfig_MEMBER_INT:
4664
481
    case PyConfig_MEMBER_UINT:
4665
481
    {
4666
481
        int value = *(int *)member;
4667
481
        return PyLong_FromLong(value);
4668
185
    }
4669
4670
1.14k
    case PyConfig_MEMBER_BOOL:
4671
1.14k
    {
4672
1.14k
        int value = *(int *)member;
4673
1.14k
        return PyBool_FromLong(value != 0);
4674
185
    }
4675
4676
37
    case PyConfig_MEMBER_ULONG:
4677
37
    {
4678
37
        unsigned long value = *(unsigned long *)member;
4679
37
        return PyLong_FromUnsignedLong(value);
4680
185
    }
4681
4682
222
    case PyConfig_MEMBER_WSTR:
4683
814
    case PyConfig_MEMBER_WSTR_OPT:
4684
814
    {
4685
814
        wchar_t *wstr = *(wchar_t **)member;
4686
814
        if (wstr != NULL) {
4687
185
            return PyUnicode_FromWideChar(wstr, -1);
4688
185
        }
4689
629
        else {
4690
629
            return Py_NewRef(Py_None);
4691
629
        }
4692
814
    }
4693
4694
185
    case PyConfig_MEMBER_WSTR_LIST:
4695
185
    {
4696
185
        if (strcmp(spec->name, "xoptions") == 0) {
4697
37
            return _PyConfig_CreateXOptionsDict(config);
4698
37
        }
4699
148
        else {
4700
148
            const PyWideStringList *list = (const PyWideStringList *)member;
4701
148
            return _PyWideStringList_AsTuple(list);
4702
148
        }
4703
185
    }
4704
4705
0
    default:
4706
0
        Py_UNREACHABLE();
4707
2.66k
    }
4708
2.66k
}
4709
4710
4711
static PyObject*
4712
preconfig_get(const PyPreConfig *preconfig, const PyConfigSpec *spec)
4713
0
{
4714
    // The type of all PYPRECONFIG_SPEC members is INT or BOOL.
4715
0
    assert(spec->type == PyConfig_MEMBER_INT
4716
0
           || spec->type == PyConfig_MEMBER_BOOL);
4717
4718
0
    char *member = (char *)preconfig + spec->offset;
4719
0
    int value = *(int *)member;
4720
4721
0
    if (spec->type == PyConfig_MEMBER_BOOL) {
4722
0
        return PyBool_FromLong(value != 0);
4723
0
    }
4724
0
    else {
4725
0
        return PyLong_FromLong(value);
4726
0
    }
4727
0
}
4728
4729
4730
static void
4731
config_unknown_name_error(const char *name)
4732
0
{
4733
0
    PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name);
4734
0
}
4735
4736
4737
PyObject*
4738
PyConfig_Get(const char *name)
4739
0
{
4740
0
    const PyConfigSpec *spec = config_find_spec(name);
4741
0
    if (spec != NULL) {
4742
0
        const PyConfig *config = _Py_GetConfig();
4743
0
        return config_get(config, spec, 1);
4744
0
    }
4745
4746
0
    spec = preconfig_find_spec(name);
4747
0
    if (spec != NULL) {
4748
0
        const PyPreConfig *preconfig = &_PyRuntime.preconfig;
4749
0
        return preconfig_get(preconfig, spec);
4750
0
    }
4751
4752
0
    config_unknown_name_error(name);
4753
0
    return NULL;
4754
0
}
4755
4756
4757
int
4758
PyConfig_GetInt(const char *name, int *value)
4759
0
{
4760
0
    assert(!PyErr_Occurred());
4761
4762
0
    PyObject *obj = PyConfig_Get(name);
4763
0
    if (obj == NULL) {
4764
0
        return -1;
4765
0
    }
4766
4767
0
    if (!PyLong_Check(obj)) {
4768
0
        Py_DECREF(obj);
4769
0
        PyErr_Format(PyExc_TypeError, "config option %s is not an int", name);
4770
0
        return -1;
4771
0
    }
4772
4773
0
    int as_int = PyLong_AsInt(obj);
4774
0
    Py_DECREF(obj);
4775
0
    if (as_int == -1 && PyErr_Occurred()) {
4776
0
        PyErr_Format(PyExc_OverflowError,
4777
0
                     "config option %s value does not fit into a C int", name);
4778
0
        return -1;
4779
0
    }
4780
4781
0
    *value = as_int;
4782
0
    return 0;
4783
0
}
4784
4785
4786
static int
4787
config_names_add(PyObject *names, const PyConfigSpec *spec)
4788
0
{
4789
0
    for (; spec->name != NULL; spec++) {
4790
0
        if (spec->visibility == PyConfig_MEMBER_INIT_ONLY) {
4791
0
            continue;
4792
0
        }
4793
0
        PyObject *name = PyUnicode_FromString(spec->name);
4794
0
        if (name == NULL) {
4795
0
            return -1;
4796
0
        }
4797
0
        int res = PyList_Append(names, name);
4798
0
        Py_DECREF(name);
4799
0
        if (res < 0) {
4800
0
            return -1;
4801
0
        }
4802
0
    }
4803
0
    return 0;
4804
0
}
4805
4806
4807
PyObject*
4808
PyConfig_Names(void)
4809
0
{
4810
0
    PyObject *names = PyList_New(0);
4811
0
    if (names == NULL) {
4812
0
        goto error;
4813
0
    }
4814
4815
0
    if (config_names_add(names, PYCONFIG_SPEC) < 0) {
4816
0
        goto error;
4817
0
    }
4818
0
    if (config_names_add(names, PYPRECONFIG_SPEC) < 0) {
4819
0
        goto error;
4820
0
    }
4821
4822
0
    PyObject *frozen = PyFrozenSet_New(names);
4823
0
    Py_DECREF(names);
4824
0
    return frozen;
4825
4826
0
error:
4827
0
    Py_XDECREF(names);
4828
0
    return NULL;
4829
0
}
4830
4831
4832
// --- PyConfig_Set() -------------------------------------------------------
4833
4834
static int
4835
config_set_sys_flag(const PyConfigSpec *spec, int int_value)
4836
0
{
4837
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
4838
0
    PyConfig *config = &interp->config;
4839
4840
0
    if (spec->type == PyConfig_MEMBER_BOOL) {
4841
0
        if (int_value != 0) {
4842
            // convert values < 0 and values > 1 to 1
4843
0
            int_value = 1;
4844
0
        }
4845
0
    }
4846
4847
0
    PyObject *value;
4848
0
    if (spec->sys.flag_setter) {
4849
0
        value = spec->sys.flag_setter(int_value);
4850
0
    }
4851
0
    else {
4852
0
        value = config_sys_flag_long(int_value);
4853
0
    }
4854
0
    if (value == NULL) {
4855
0
        return -1;
4856
0
    }
4857
4858
    // Set sys.flags.FLAG
4859
0
    Py_ssize_t pos = spec->sys.flag_index;
4860
0
    if (_PySys_SetFlagObj(pos, value) < 0) {
4861
0
        goto error;
4862
0
    }
4863
4864
    // Set PyConfig.ATTR
4865
0
    assert(spec->type == PyConfig_MEMBER_INT
4866
0
           || spec->type == PyConfig_MEMBER_UINT
4867
0
           || spec->type == PyConfig_MEMBER_BOOL);
4868
0
    int *member = config_get_spec_member(config, spec);
4869
0
    *member = int_value;
4870
4871
    // Set sys.dont_write_bytecode attribute
4872
0
    if (strcmp(spec->name, "write_bytecode") == 0) {
4873
0
        if (PySys_SetObject("dont_write_bytecode", value) < 0) {
4874
0
            goto error;
4875
0
        }
4876
0
    }
4877
4878
0
    Py_DECREF(value);
4879
0
    return 0;
4880
4881
0
error:
4882
0
    Py_DECREF(value);
4883
0
    return -1;
4884
0
}
4885
4886
4887
// Set PyConfig.ATTR integer member
4888
static int
4889
config_set_int_attr(const PyConfigSpec *spec, int value)
4890
0
{
4891
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
4892
0
    PyConfig *config = &interp->config;
4893
0
    int *member = config_get_spec_member(config, spec);
4894
0
    *member = value;
4895
0
    return 0;
4896
0
}
4897
4898
4899
int
4900
PyConfig_Set(const char *name, PyObject *value)
4901
0
{
4902
0
    if (PySys_Audit("cpython.PyConfig_Set", "sO", name, value) < 0) {
4903
0
        return -1;
4904
0
    }
4905
4906
0
    const PyConfigSpec *spec = config_find_spec(name);
4907
0
    if (spec == NULL) {
4908
0
        spec = preconfig_find_spec(name);
4909
0
        if (spec == NULL) {
4910
0
            config_unknown_name_error(name);
4911
0
            return -1;
4912
0
        }
4913
0
        assert(spec->visibility != PyConfig_MEMBER_PUBLIC);
4914
0
    }
4915
4916
0
    if (spec->visibility != PyConfig_MEMBER_PUBLIC) {
4917
0
        PyErr_Format(PyExc_ValueError, "cannot set read-only option %s",
4918
0
                     name);
4919
0
        return -1;
4920
0
    }
4921
4922
0
    int int_value = 0;
4923
0
    int has_int_value = 0;
4924
4925
0
    switch (spec->type) {
4926
0
    case PyConfig_MEMBER_INT:
4927
0
    case PyConfig_MEMBER_UINT:
4928
0
    case PyConfig_MEMBER_BOOL:
4929
0
        if (!PyLong_Check(value)) {
4930
0
            PyErr_Format(PyExc_TypeError, "expected int or bool, got %T", value);
4931
0
            return -1;
4932
0
        }
4933
0
        int_value = PyLong_AsInt(value);
4934
0
        if (int_value == -1 && PyErr_Occurred()) {
4935
0
            return -1;
4936
0
        }
4937
0
        if (int_value < 0 && spec->type != PyConfig_MEMBER_INT) {
4938
0
            PyErr_Format(PyExc_ValueError, "value must be >= 0");
4939
0
            return -1;
4940
0
        }
4941
0
        has_int_value = 1;
4942
0
        break;
4943
4944
0
    case PyConfig_MEMBER_ULONG:
4945
        // not implemented: only hash_seed uses this type, and it's read-only
4946
0
        goto cannot_set;
4947
4948
0
    case PyConfig_MEMBER_WSTR:
4949
0
        if (!PyUnicode_CheckExact(value)) {
4950
0
            PyErr_Format(PyExc_TypeError, "expected str, got %T", value);
4951
0
            return -1;
4952
0
        }
4953
0
        break;
4954
4955
0
    case PyConfig_MEMBER_WSTR_OPT:
4956
0
        if (value != Py_None && !PyUnicode_CheckExact(value)) {
4957
0
            PyErr_Format(PyExc_TypeError, "expected str or None, got %T", value);
4958
0
            return -1;
4959
0
        }
4960
0
        break;
4961
4962
0
    case PyConfig_MEMBER_WSTR_LIST:
4963
0
        if (strcmp(spec->name, "xoptions") != 0) {
4964
0
            if (!PyList_Check(value)) {
4965
0
                PyErr_Format(PyExc_TypeError, "expected list[str], got %T",
4966
0
                             value);
4967
0
                return -1;
4968
0
            }
4969
0
            for (Py_ssize_t i=0; i < PyList_GET_SIZE(value); i++) {
4970
0
                PyObject *item = PyList_GET_ITEM(value, i);
4971
0
                if (!PyUnicode_Check(item)) {
4972
0
                    PyErr_Format(PyExc_TypeError,
4973
0
                                 "expected str, list item %zd has type %T",
4974
0
                                 i, item);
4975
0
                    return -1;
4976
0
                }
4977
0
            }
4978
0
        }
4979
0
        else {
4980
            // xoptions type is dict[str, str]
4981
0
            if (!PyDict_Check(value)) {
4982
0
                PyErr_Format(PyExc_TypeError,
4983
0
                             "expected dict[str, str | bool], got %T",
4984
0
                             value);
4985
0
                return -1;
4986
0
            }
4987
4988
0
            Py_ssize_t pos = 0;
4989
0
            PyObject *key, *item;
4990
0
            while (PyDict_Next(value, &pos, &key, &item)) {
4991
0
                if (!PyUnicode_Check(key)) {
4992
0
                    PyErr_Format(PyExc_TypeError,
4993
0
                                 "expected str, "
4994
0
                                 "got dict key type %T", key);
4995
0
                    return -1;
4996
0
                }
4997
0
                if (!PyUnicode_Check(item) && !PyBool_Check(item)) {
4998
0
                    PyErr_Format(PyExc_TypeError,
4999
0
                                 "expected str or bool, "
5000
0
                                 "got dict value type %T", key);
5001
0
                    return -1;
5002
0
                }
5003
0
            }
5004
0
        }
5005
0
        break;
5006
5007
0
    default:
5008
0
        Py_UNREACHABLE();
5009
0
    }
5010
5011
0
    if (spec->sys.attr != NULL) {
5012
        // Set the sys attribute, but don't set PyInterpreterState.config
5013
        // to keep the code simple.
5014
0
        return PySys_SetObject(spec->sys.attr, value);
5015
0
    }
5016
0
    else if (has_int_value) {
5017
0
        if (spec->sys.flag_index >= 0) {
5018
0
            return config_set_sys_flag(spec, int_value);
5019
0
        }
5020
0
        else if (strcmp(spec->name, "int_max_str_digits") == 0) {
5021
0
            return _PySys_SetIntMaxStrDigits(int_value);
5022
0
        }
5023
0
        else {
5024
0
            return config_set_int_attr(spec, int_value);
5025
0
        }
5026
0
    }
5027
5028
0
cannot_set:
5029
0
    PyErr_Format(PyExc_ValueError, "cannot set option %s", name);
5030
0
    return -1;
5031
0
}