Coverage Report

Created: 2026-05-16 06:46

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