xref: /third_party/python/Programs/_testembed.c (revision 7db96d56)
1#ifndef Py_BUILD_CORE_MODULE
2#  define Py_BUILD_CORE_MODULE
3#endif
4#define NEEDS_PY_IDENTIFIER
5
6/* Always enable assertion (even in release mode) */
7#undef NDEBUG
8
9#include <Python.h>
10#include "pycore_initconfig.h"    // _PyConfig_InitCompatConfig()
11#include "pycore_runtime.h"       // _PyRuntime
12#include "pycore_import.h"        // _PyImport_FrozenBootstrap
13#include <Python.h>
14#include <inttypes.h>
15#include <stdio.h>
16#include <stdlib.h>               // putenv()
17#include <wchar.h>
18
19int main_argc;
20char **main_argv;
21
22/*********************************************************
23 * Embedded interpreter tests that need a custom exe
24 *
25 * Executed via Lib/test/test_embed.py
26 *********************************************************/
27
28// Use to display the usage
29#define PROGRAM "test_embed"
30
31/* Use path starting with "./" avoids a search along the PATH */
32#define PROGRAM_NAME L"./_testembed"
33
34#define INIT_LOOPS 4
35
36// Ignore Py_DEPRECATED() compiler warnings: deprecated functions are
37// tested on purpose here.
38_Py_COMP_DIAG_PUSH
39_Py_COMP_DIAG_IGNORE_DEPR_DECLS
40
41
42static void error(const char *msg)
43{
44    fprintf(stderr, "ERROR: %s\n", msg);
45    fflush(stderr);
46}
47
48
49static void config_set_string(PyConfig *config, wchar_t **config_str, const wchar_t *str)
50{
51    PyStatus status = PyConfig_SetString(config, config_str, str);
52    if (PyStatus_Exception(status)) {
53        PyConfig_Clear(config);
54        Py_ExitStatusException(status);
55    }
56}
57
58
59static void config_set_program_name(PyConfig *config)
60{
61    const wchar_t *program_name = PROGRAM_NAME;
62    config_set_string(config, &config->program_name, program_name);
63}
64
65
66static void init_from_config_clear(PyConfig *config)
67{
68    PyStatus status = Py_InitializeFromConfig(config);
69    PyConfig_Clear(config);
70    if (PyStatus_Exception(status)) {
71        Py_ExitStatusException(status);
72    }
73}
74
75
76static void _testembed_Py_InitializeFromConfig(void)
77{
78    PyConfig config;
79    _PyConfig_InitCompatConfig(&config);
80    config_set_program_name(&config);
81    init_from_config_clear(&config);
82}
83
84static void _testembed_Py_Initialize(void)
85{
86   Py_SetProgramName(PROGRAM_NAME);
87   Py_Initialize();
88}
89
90
91/*****************************************************
92 * Test repeated initialisation and subinterpreters
93 *****************************************************/
94
95static void print_subinterp(void)
96{
97    /* Output information about the interpreter in the format
98       expected in Lib/test/test_capi.py (test_subinterps). */
99    PyThreadState *ts = PyThreadState_Get();
100    PyInterpreterState *interp = ts->interp;
101    int64_t id = PyInterpreterState_GetID(interp);
102    printf("interp %" PRId64 " <0x%" PRIXPTR ">, thread state <0x%" PRIXPTR ">: ",
103            id, (uintptr_t)interp, (uintptr_t)ts);
104    fflush(stdout);
105    PyRun_SimpleString(
106        "import sys;"
107        "print('id(modules) =', id(sys.modules));"
108        "sys.stdout.flush()"
109    );
110}
111
112static int test_repeated_init_and_subinterpreters(void)
113{
114    PyThreadState *mainstate, *substate;
115    PyGILState_STATE gilstate;
116
117    for (int i=1; i <= INIT_LOOPS; i++) {
118        printf("--- Pass %d ---\n", i);
119        _testembed_Py_InitializeFromConfig();
120        mainstate = PyThreadState_Get();
121
122        PyEval_ReleaseThread(mainstate);
123
124        gilstate = PyGILState_Ensure();
125        print_subinterp();
126        PyThreadState_Swap(NULL);
127
128        for (int j=0; j<3; j++) {
129            substate = Py_NewInterpreter();
130            print_subinterp();
131            Py_EndInterpreter(substate);
132        }
133
134        PyThreadState_Swap(mainstate);
135        print_subinterp();
136        PyGILState_Release(gilstate);
137
138        PyEval_RestoreThread(mainstate);
139        Py_Finalize();
140    }
141    return 0;
142}
143
144#define EMBEDDED_EXT_NAME "embedded_ext"
145
146static PyModuleDef embedded_ext = {
147    PyModuleDef_HEAD_INIT,
148    .m_name = EMBEDDED_EXT_NAME,
149    .m_size = 0,
150};
151
152static PyObject*
153PyInit_embedded_ext(void)
154{
155    return PyModule_Create(&embedded_ext);
156}
157
158/****************************************************************************
159 * Call Py_Initialize()/Py_Finalize() multiple times and execute Python code
160 ***************************************************************************/
161
162// Used by bpo-46417 to test that structseq types used by the sys module are
163// cleared properly and initialized again properly when Python is finalized
164// multiple times.
165static int test_repeated_init_exec(void)
166{
167    if (main_argc < 3) {
168        fprintf(stderr, "usage: %s test_repeated_init_exec CODE\n", PROGRAM);
169        exit(1);
170    }
171    const char *code = main_argv[2];
172
173    for (int i=1; i <= INIT_LOOPS; i++) {
174        fprintf(stderr, "--- Loop #%d ---\n", i);
175        fflush(stderr);
176
177        _testembed_Py_InitializeFromConfig();
178        int err = PyRun_SimpleString(code);
179        Py_Finalize();
180        if (err) {
181            return 1;
182        }
183    }
184    return 0;
185}
186
187/****************************************************************************
188 * Test the Py_Initialize(Ex) convenience/compatibility wrappers
189 ***************************************************************************/
190// This is here to help ensure there are no wrapper resource leaks (gh-96853)
191static int test_repeated_simple_init(void)
192{
193    for (int i=1; i <= INIT_LOOPS; i++) {
194        fprintf(stderr, "--- Loop #%d ---\n", i);
195        fflush(stderr);
196
197        _testembed_Py_Initialize();
198        Py_Finalize();
199        printf("Finalized\n"); // Give test_embed some output to check
200    }
201    return 0;
202}
203
204
205/*****************************************************
206 * Test forcing a particular IO encoding
207 *****************************************************/
208
209static void check_stdio_details(const char *encoding, const char * errors)
210{
211    /* Output info for the test case to check */
212    if (encoding) {
213        printf("Expected encoding: %s\n", encoding);
214    } else {
215        printf("Expected encoding: default\n");
216    }
217    if (errors) {
218        printf("Expected errors: %s\n", errors);
219    } else {
220        printf("Expected errors: default\n");
221    }
222    fflush(stdout);
223    /* Force the given IO encoding */
224    Py_SetStandardStreamEncoding(encoding, errors);
225    _testembed_Py_InitializeFromConfig();
226    PyRun_SimpleString(
227        "import sys;"
228        "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));"
229        "print('stdout: {0.encoding}:{0.errors}'.format(sys.stdout));"
230        "print('stderr: {0.encoding}:{0.errors}'.format(sys.stderr));"
231        "sys.stdout.flush()"
232    );
233    Py_Finalize();
234}
235
236static int test_forced_io_encoding(void)
237{
238    /* Check various combinations */
239    printf("--- Use defaults ---\n");
240    check_stdio_details(NULL, NULL);
241    printf("--- Set errors only ---\n");
242    check_stdio_details(NULL, "ignore");
243    printf("--- Set encoding only ---\n");
244    check_stdio_details("iso8859-1", NULL);
245    printf("--- Set encoding and errors ---\n");
246    check_stdio_details("iso8859-1", "replace");
247
248    /* Check calling after initialization fails */
249    Py_Initialize();
250
251    if (Py_SetStandardStreamEncoding(NULL, NULL) == 0) {
252        printf("Unexpected success calling Py_SetStandardStreamEncoding");
253    }
254    Py_Finalize();
255    return 0;
256}
257
258/*********************************************************
259 * Test parts of the C-API that work before initialization
260 *********************************************************/
261
262/* The pre-initialization tests tend to break by segfaulting, so explicitly
263 * flushed progress messages make the broken API easier to find when they fail.
264 */
265#define _Py_EMBED_PREINIT_CHECK(msg) \
266    do {printf(msg); fflush(stdout);} while (0);
267
268static int test_pre_initialization_api(void)
269{
270    /* the test doesn't support custom memory allocators */
271    putenv("PYTHONMALLOC=");
272
273    /* Leading "./" ensures getpath.c can still find the standard library */
274    _Py_EMBED_PREINIT_CHECK("Checking Py_DecodeLocale\n");
275    wchar_t *program = Py_DecodeLocale("./spam", NULL);
276    if (program == NULL) {
277        fprintf(stderr, "Fatal error: cannot decode program name\n");
278        return 1;
279    }
280    _Py_EMBED_PREINIT_CHECK("Checking Py_SetProgramName\n");
281    Py_SetProgramName(program);
282
283    _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
284    Py_Initialize();
285    _Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
286    PyRun_SimpleString("import sys; "
287                       "print('sys.executable:', sys.executable)");
288    _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n");
289    Py_Finalize();
290
291    _Py_EMBED_PREINIT_CHECK("Freeing memory allocated by Py_DecodeLocale\n");
292    PyMem_RawFree(program);
293    return 0;
294}
295
296
297/* bpo-33042: Ensure embedding apps can predefine sys module options */
298static int test_pre_initialization_sys_options(void)
299{
300    /* We allocate a couple of the options dynamically, and then delete
301     * them before calling Py_Initialize. This ensures the interpreter isn't
302     * relying on the caller to keep the passed in strings alive.
303     */
304    const wchar_t *static_warnoption = L"once";
305    const wchar_t *static_xoption = L"also_not_an_option=2";
306    size_t warnoption_len = wcslen(static_warnoption);
307    size_t xoption_len = wcslen(static_xoption);
308    wchar_t *dynamic_once_warnoption = \
309             (wchar_t *) calloc(warnoption_len+1, sizeof(wchar_t));
310    wchar_t *dynamic_xoption = \
311             (wchar_t *) calloc(xoption_len+1, sizeof(wchar_t));
312    wcsncpy(dynamic_once_warnoption, static_warnoption, warnoption_len+1);
313    wcsncpy(dynamic_xoption, static_xoption, xoption_len+1);
314
315    _Py_EMBED_PREINIT_CHECK("Checking PySys_AddWarnOption\n");
316    PySys_AddWarnOption(L"default");
317    _Py_EMBED_PREINIT_CHECK("Checking PySys_ResetWarnOptions\n");
318    PySys_ResetWarnOptions();
319    _Py_EMBED_PREINIT_CHECK("Checking PySys_AddWarnOption linked list\n");
320    PySys_AddWarnOption(dynamic_once_warnoption);
321    PySys_AddWarnOption(L"module");
322    PySys_AddWarnOption(L"default");
323    _Py_EMBED_PREINIT_CHECK("Checking PySys_AddXOption\n");
324    PySys_AddXOption(L"not_an_option=1");
325    PySys_AddXOption(dynamic_xoption);
326
327    /* Delete the dynamic options early */
328    free(dynamic_once_warnoption);
329    dynamic_once_warnoption = NULL;
330    free(dynamic_xoption);
331    dynamic_xoption = NULL;
332
333    _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
334    _testembed_Py_InitializeFromConfig();
335    _Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
336    PyRun_SimpleString("import sys; "
337                       "print('sys.warnoptions:', sys.warnoptions); "
338                       "print('sys._xoptions:', sys._xoptions); "
339                       "warnings = sys.modules['warnings']; "
340                       "latest_filters = [f[0] for f in warnings.filters[:3]]; "
341                       "print('warnings.filters[:3]:', latest_filters)");
342    _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n");
343    Py_Finalize();
344
345    return 0;
346}
347
348
349/* bpo-20891: Avoid race condition when initialising the GIL */
350static void bpo20891_thread(void *lockp)
351{
352    PyThread_type_lock lock = *((PyThread_type_lock*)lockp);
353
354    PyGILState_STATE state = PyGILState_Ensure();
355    if (!PyGILState_Check()) {
356        error("PyGILState_Check failed!");
357        abort();
358    }
359
360    PyGILState_Release(state);
361
362    PyThread_release_lock(lock);
363}
364
365static int test_bpo20891(void)
366{
367    /* the test doesn't support custom memory allocators */
368    putenv("PYTHONMALLOC=");
369
370    /* bpo-20891: Calling PyGILState_Ensure in a non-Python thread must not
371       crash. */
372    PyThread_type_lock lock = PyThread_allocate_lock();
373    if (!lock) {
374        error("PyThread_allocate_lock failed!");
375        return 1;
376    }
377
378    _testembed_Py_InitializeFromConfig();
379
380    unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock);
381    if (thrd == PYTHREAD_INVALID_THREAD_ID) {
382        error("PyThread_start_new_thread failed!");
383        return 1;
384    }
385    PyThread_acquire_lock(lock, WAIT_LOCK);
386
387    Py_BEGIN_ALLOW_THREADS
388    /* wait until the thread exit */
389    PyThread_acquire_lock(lock, WAIT_LOCK);
390    Py_END_ALLOW_THREADS
391
392    PyThread_free_lock(lock);
393
394    Py_Finalize();
395
396    return 0;
397}
398
399static int test_initialize_twice(void)
400{
401    _testembed_Py_InitializeFromConfig();
402
403    /* bpo-33932: Calling Py_Initialize() twice should do nothing
404     * (and not crash!). */
405    Py_Initialize();
406
407    Py_Finalize();
408
409    return 0;
410}
411
412static int test_initialize_pymain(void)
413{
414    wchar_t *argv[] = {L"PYTHON", L"-c",
415                       (L"import sys; "
416                        L"print(f'Py_Main() after Py_Initialize: "
417                        L"sys.argv={sys.argv}')"),
418                       L"arg2"};
419    _testembed_Py_InitializeFromConfig();
420
421    /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */
422    Py_Main(Py_ARRAY_LENGTH(argv), argv);
423
424    Py_Finalize();
425
426    return 0;
427}
428
429
430static void
431dump_config(void)
432{
433    (void) PyRun_SimpleStringFlags(
434        "import _testinternalcapi, json; "
435        "print(json.dumps(_testinternalcapi.get_configs()))",
436        0);
437}
438
439
440static int test_init_initialize_config(void)
441{
442    _testembed_Py_InitializeFromConfig();
443    dump_config();
444    Py_Finalize();
445    return 0;
446}
447
448
449static void config_set_argv(PyConfig *config, Py_ssize_t argc, wchar_t * const *argv)
450{
451    PyStatus status = PyConfig_SetArgv(config, argc, argv);
452    if (PyStatus_Exception(status)) {
453        PyConfig_Clear(config);
454        Py_ExitStatusException(status);
455    }
456}
457
458
459static void
460config_set_wide_string_list(PyConfig *config, PyWideStringList *list,
461                            Py_ssize_t length, wchar_t **items)
462{
463    PyStatus status = PyConfig_SetWideStringList(config, list, length, items);
464    if (PyStatus_Exception(status)) {
465        PyConfig_Clear(config);
466        Py_ExitStatusException(status);
467    }
468}
469
470
471static int check_init_compat_config(int preinit)
472{
473    PyStatus status;
474
475    if (preinit) {
476        PyPreConfig preconfig;
477        _PyPreConfig_InitCompatConfig(&preconfig);
478
479        status = Py_PreInitialize(&preconfig);
480        if (PyStatus_Exception(status)) {
481            Py_ExitStatusException(status);
482        }
483    }
484
485    PyConfig config;
486    _PyConfig_InitCompatConfig(&config);
487
488    config_set_program_name(&config);
489    init_from_config_clear(&config);
490
491    dump_config();
492    Py_Finalize();
493    return 0;
494}
495
496
497static int test_preinit_compat_config(void)
498{
499    return check_init_compat_config(1);
500}
501
502
503static int test_init_compat_config(void)
504{
505    return check_init_compat_config(0);
506}
507
508
509static int test_init_global_config(void)
510{
511    /* FIXME: test Py_IgnoreEnvironmentFlag */
512
513    putenv("PYTHONUTF8=0");
514    Py_UTF8Mode = 1;
515
516    /* Test initialization from global configuration variables (Py_xxx) */
517    Py_SetProgramName(L"./globalvar");
518
519    /* Py_IsolatedFlag is not tested */
520    Py_NoSiteFlag = 1;
521    Py_BytesWarningFlag = 1;
522
523    putenv("PYTHONINSPECT=");
524    Py_InspectFlag = 1;
525
526    putenv("PYTHONOPTIMIZE=0");
527    Py_InteractiveFlag = 1;
528
529    putenv("PYTHONDEBUG=0");
530    Py_OptimizeFlag = 2;
531
532    /* Py_DebugFlag is not tested */
533
534    putenv("PYTHONDONTWRITEBYTECODE=");
535    Py_DontWriteBytecodeFlag = 1;
536
537    putenv("PYTHONVERBOSE=0");
538    Py_VerboseFlag = 1;
539
540    Py_QuietFlag = 1;
541    Py_NoUserSiteDirectory = 1;
542
543    putenv("PYTHONUNBUFFERED=");
544    Py_UnbufferedStdioFlag = 1;
545
546    Py_FrozenFlag = 1;
547
548    /* FIXME: test Py_LegacyWindowsFSEncodingFlag */
549    /* FIXME: test Py_LegacyWindowsStdioFlag */
550
551    Py_Initialize();
552    dump_config();
553    Py_Finalize();
554    return 0;
555}
556
557
558static int test_init_from_config(void)
559{
560    PyPreConfig preconfig;
561    _PyPreConfig_InitCompatConfig(&preconfig);
562
563    putenv("PYTHONMALLOC=malloc_debug");
564    preconfig.allocator = PYMEM_ALLOCATOR_MALLOC;
565
566    putenv("PYTHONUTF8=0");
567    Py_UTF8Mode = 0;
568    preconfig.utf8_mode = 1;
569
570    PyStatus status = Py_PreInitialize(&preconfig);
571    if (PyStatus_Exception(status)) {
572        Py_ExitStatusException(status);
573    }
574
575    PyConfig config;
576    _PyConfig_InitCompatConfig(&config);
577
578    config.install_signal_handlers = 0;
579
580    /* FIXME: test use_environment */
581
582    putenv("PYTHONHASHSEED=42");
583    config.use_hash_seed = 1;
584    config.hash_seed = 123;
585
586    /* dev_mode=1 is tested in test_init_dev_mode() */
587
588    putenv("PYTHONFAULTHANDLER=");
589    config.faulthandler = 1;
590
591    putenv("PYTHONTRACEMALLOC=0");
592    config.tracemalloc = 2;
593
594    putenv("PYTHONPROFILEIMPORTTIME=0");
595    config.import_time = 1;
596
597    putenv("PYTHONNODEBUGRANGES=0");
598    config.code_debug_ranges = 0;
599
600    config.show_ref_count = 1;
601    /* FIXME: test dump_refs: bpo-34223 */
602
603    putenv("PYTHONMALLOCSTATS=0");
604    config.malloc_stats = 1;
605
606    putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
607    config_set_string(&config, &config.pycache_prefix, L"conf_pycache_prefix");
608
609    Py_SetProgramName(L"./globalvar");
610    config_set_string(&config, &config.program_name, L"./conf_program_name");
611
612    wchar_t* argv[] = {
613        L"python3",
614        L"-W",
615        L"cmdline_warnoption",
616        L"-X",
617        L"cmdline_xoption",
618        L"-c",
619        L"pass",
620        L"arg2",
621    };
622    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
623    config.parse_argv = 1;
624
625    wchar_t* xoptions[3] = {
626        L"config_xoption1=3",
627        L"config_xoption2=",
628        L"config_xoption3",
629    };
630    config_set_wide_string_list(&config, &config.xoptions,
631                                Py_ARRAY_LENGTH(xoptions), xoptions);
632
633    wchar_t* warnoptions[1] = {
634        L"config_warnoption",
635    };
636    config_set_wide_string_list(&config, &config.warnoptions,
637                                Py_ARRAY_LENGTH(warnoptions), warnoptions);
638
639    /* FIXME: test pythonpath_env */
640    /* FIXME: test home */
641    /* FIXME: test path config: module_search_path .. dll_path */
642
643    putenv("PYTHONPLATLIBDIR=env_platlibdir");
644    status = PyConfig_SetBytesString(&config, &config.platlibdir, "my_platlibdir");
645    if (PyStatus_Exception(status)) {
646        PyConfig_Clear(&config);
647        Py_ExitStatusException(status);
648    }
649
650    putenv("PYTHONVERBOSE=0");
651    Py_VerboseFlag = 0;
652    config.verbose = 1;
653
654    Py_NoSiteFlag = 0;
655    config.site_import = 0;
656
657    Py_BytesWarningFlag = 0;
658    config.bytes_warning = 1;
659
660    putenv("PYTHONINSPECT=");
661    Py_InspectFlag = 0;
662    config.inspect = 1;
663
664    Py_InteractiveFlag = 0;
665    config.interactive = 1;
666
667    putenv("PYTHONOPTIMIZE=0");
668    Py_OptimizeFlag = 1;
669    config.optimization_level = 2;
670
671    /* FIXME: test parser_debug */
672
673    putenv("PYTHONDONTWRITEBYTECODE=");
674    Py_DontWriteBytecodeFlag = 0;
675    config.write_bytecode = 0;
676
677    Py_QuietFlag = 0;
678    config.quiet = 1;
679
680    config.configure_c_stdio = 1;
681
682    putenv("PYTHONUNBUFFERED=");
683    Py_UnbufferedStdioFlag = 0;
684    config.buffered_stdio = 0;
685
686    putenv("PYTHONIOENCODING=cp424");
687    Py_SetStandardStreamEncoding("ascii", "ignore");
688#ifdef MS_WINDOWS
689    /* Py_SetStandardStreamEncoding() sets Py_LegacyWindowsStdioFlag to 1.
690       Force it to 0 through the config. */
691    config.legacy_windows_stdio = 0;
692#endif
693    config_set_string(&config, &config.stdio_encoding, L"iso8859-1");
694    config_set_string(&config, &config.stdio_errors, L"replace");
695
696    putenv("PYTHONNOUSERSITE=");
697    Py_NoUserSiteDirectory = 0;
698    config.user_site_directory = 0;
699
700    config_set_string(&config, &config.check_hash_pycs_mode, L"always");
701
702    Py_FrozenFlag = 0;
703    config.pathconfig_warnings = 0;
704
705    config.safe_path = 1;
706
707    config._isolated_interpreter = 1;
708
709    init_from_config_clear(&config);
710
711    dump_config();
712    Py_Finalize();
713    return 0;
714}
715
716
717static int check_init_parse_argv(int parse_argv)
718{
719    PyConfig config;
720    PyConfig_InitPythonConfig(&config);
721
722    config.parse_argv = parse_argv;
723
724    wchar_t* argv[] = {
725        L"./argv0",
726        L"-E",
727        L"-c",
728        L"pass",
729        L"arg1",
730        L"-v",
731        L"arg3",
732    };
733    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
734    init_from_config_clear(&config);
735
736    dump_config();
737    Py_Finalize();
738    return 0;
739}
740
741
742static int test_init_parse_argv(void)
743{
744    return check_init_parse_argv(1);
745}
746
747
748static int test_init_dont_parse_argv(void)
749{
750    return check_init_parse_argv(0);
751}
752
753
754static void set_most_env_vars(void)
755{
756    putenv("PYTHONHASHSEED=42");
757    putenv("PYTHONMALLOC=malloc");
758    putenv("PYTHONTRACEMALLOC=2");
759    putenv("PYTHONPROFILEIMPORTTIME=1");
760    putenv("PYTHONNODEBUGRANGES=1");
761    putenv("PYTHONMALLOCSTATS=1");
762    putenv("PYTHONUTF8=1");
763    putenv("PYTHONVERBOSE=1");
764    putenv("PYTHONINSPECT=1");
765    putenv("PYTHONOPTIMIZE=2");
766    putenv("PYTHONDONTWRITEBYTECODE=1");
767    putenv("PYTHONUNBUFFERED=1");
768    putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
769    putenv("PYTHONNOUSERSITE=1");
770    putenv("PYTHONFAULTHANDLER=1");
771    putenv("PYTHONIOENCODING=iso8859-1:replace");
772    putenv("PYTHONPLATLIBDIR=env_platlibdir");
773    putenv("PYTHONSAFEPATH=1");
774}
775
776
777static void set_all_env_vars(void)
778{
779    set_most_env_vars();
780
781    putenv("PYTHONWARNINGS=EnvVar");
782    putenv("PYTHONPATH=/my/path");
783}
784
785
786static int test_init_compat_env(void)
787{
788    /* Test initialization from environment variables */
789    Py_IgnoreEnvironmentFlag = 0;
790    set_all_env_vars();
791    _testembed_Py_InitializeFromConfig();
792    dump_config();
793    Py_Finalize();
794    return 0;
795}
796
797
798static int test_init_python_env(void)
799{
800    set_all_env_vars();
801
802    PyConfig config;
803    PyConfig_InitPythonConfig(&config);
804
805    config_set_program_name(&config);
806    init_from_config_clear(&config);
807
808    dump_config();
809    Py_Finalize();
810    return 0;
811}
812
813
814static void set_all_env_vars_dev_mode(void)
815{
816    putenv("PYTHONMALLOC=");
817    putenv("PYTHONFAULTHANDLER=");
818    putenv("PYTHONDEVMODE=1");
819}
820
821
822static int test_init_env_dev_mode(void)
823{
824    /* Test initialization from environment variables */
825    Py_IgnoreEnvironmentFlag = 0;
826    set_all_env_vars_dev_mode();
827    _testembed_Py_InitializeFromConfig();
828    dump_config();
829    Py_Finalize();
830    return 0;
831}
832
833
834static int test_init_env_dev_mode_alloc(void)
835{
836    /* Test initialization from environment variables */
837    Py_IgnoreEnvironmentFlag = 0;
838    set_all_env_vars_dev_mode();
839    putenv("PYTHONMALLOC=malloc");
840    _testembed_Py_InitializeFromConfig();
841    dump_config();
842    Py_Finalize();
843    return 0;
844}
845
846
847static int test_init_isolated_flag(void)
848{
849    /* Test PyConfig.isolated=1 */
850    PyConfig config;
851    PyConfig_InitPythonConfig(&config);
852
853    Py_IsolatedFlag = 0;
854    config.isolated = 1;
855    // These options are set to 1 by isolated=1
856    config.safe_path = 0;
857    config.use_environment = 1;
858    config.user_site_directory = 1;
859
860    config_set_program_name(&config);
861    set_all_env_vars();
862    init_from_config_clear(&config);
863
864    dump_config();
865    Py_Finalize();
866    return 0;
867}
868
869
870/* PyPreConfig.isolated=1, PyConfig.isolated=0 */
871static int test_preinit_isolated1(void)
872{
873    PyPreConfig preconfig;
874    _PyPreConfig_InitCompatConfig(&preconfig);
875
876    preconfig.isolated = 1;
877
878    PyStatus status = Py_PreInitialize(&preconfig);
879    if (PyStatus_Exception(status)) {
880        Py_ExitStatusException(status);
881    }
882
883    PyConfig config;
884    _PyConfig_InitCompatConfig(&config);
885
886    config_set_program_name(&config);
887    set_all_env_vars();
888    init_from_config_clear(&config);
889
890    dump_config();
891    Py_Finalize();
892    return 0;
893}
894
895
896/* PyPreConfig.isolated=0, PyConfig.isolated=1 */
897static int test_preinit_isolated2(void)
898{
899    PyPreConfig preconfig;
900    _PyPreConfig_InitCompatConfig(&preconfig);
901
902    preconfig.isolated = 0;
903
904    PyStatus status = Py_PreInitialize(&preconfig);
905    if (PyStatus_Exception(status)) {
906        Py_ExitStatusException(status);
907    }
908
909    /* Test PyConfig.isolated=1 */
910    PyConfig config;
911    _PyConfig_InitCompatConfig(&config);
912
913    Py_IsolatedFlag = 0;
914    config.isolated = 1;
915
916    config_set_program_name(&config);
917    set_all_env_vars();
918    init_from_config_clear(&config);
919
920    dump_config();
921    Py_Finalize();
922    return 0;
923}
924
925
926static int test_preinit_dont_parse_argv(void)
927{
928    PyPreConfig preconfig;
929    PyPreConfig_InitIsolatedConfig(&preconfig);
930
931    preconfig.isolated = 0;
932
933    /* -X dev must be ignored by isolated preconfiguration */
934    wchar_t *argv[] = {L"python3",
935                       L"-E",
936                       L"-I",
937                       L"-P",
938                       L"-X", L"dev",
939                       L"-X", L"utf8",
940                       L"script.py"};
941    PyStatus status = Py_PreInitializeFromArgs(&preconfig,
942                                               Py_ARRAY_LENGTH(argv), argv);
943    if (PyStatus_Exception(status)) {
944        Py_ExitStatusException(status);
945    }
946
947    PyConfig config;
948    PyConfig_InitIsolatedConfig(&config);
949
950    config.isolated = 0;
951
952    /* Pre-initialize implicitly using argv: make sure that -X dev
953       is used to configure the allocation in preinitialization */
954    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
955    config_set_program_name(&config);
956    init_from_config_clear(&config);
957
958    dump_config();
959    Py_Finalize();
960    return 0;
961}
962
963
964static int test_preinit_parse_argv(void)
965{
966    PyConfig config;
967    PyConfig_InitPythonConfig(&config);
968
969    /* Pre-initialize implicitly using argv: make sure that -X dev
970       is used to configure the allocation in preinitialization */
971    wchar_t *argv[] = {L"python3", L"-X", L"dev", L"-P", L"script.py"};
972    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
973    config_set_program_name(&config);
974    init_from_config_clear(&config);
975
976    dump_config();
977    Py_Finalize();
978    return 0;
979}
980
981
982
983
984static void set_all_global_config_variables(void)
985{
986    Py_IsolatedFlag = 0;
987    Py_IgnoreEnvironmentFlag = 0;
988    Py_BytesWarningFlag = 2;
989    Py_InspectFlag = 1;
990    Py_InteractiveFlag = 1;
991    Py_OptimizeFlag = 1;
992    Py_DebugFlag = 1;
993    Py_VerboseFlag = 1;
994    Py_QuietFlag = 1;
995    Py_FrozenFlag = 0;
996    Py_UnbufferedStdioFlag = 1;
997    Py_NoSiteFlag = 1;
998    Py_DontWriteBytecodeFlag = 1;
999    Py_NoUserSiteDirectory = 1;
1000#ifdef MS_WINDOWS
1001    Py_LegacyWindowsStdioFlag = 1;
1002#endif
1003}
1004
1005
1006static int check_preinit_isolated_config(int preinit)
1007{
1008    PyStatus status;
1009    PyPreConfig *rt_preconfig;
1010
1011    /* environment variables must be ignored */
1012    set_all_env_vars();
1013
1014    /* global configuration variables must be ignored */
1015    set_all_global_config_variables();
1016
1017    if (preinit) {
1018        PyPreConfig preconfig;
1019        PyPreConfig_InitIsolatedConfig(&preconfig);
1020
1021        status = Py_PreInitialize(&preconfig);
1022        if (PyStatus_Exception(status)) {
1023            Py_ExitStatusException(status);
1024        }
1025
1026        rt_preconfig = &_PyRuntime.preconfig;
1027        assert(rt_preconfig->isolated == 1);
1028        assert(rt_preconfig->use_environment == 0);
1029    }
1030
1031    PyConfig config;
1032    PyConfig_InitIsolatedConfig(&config);
1033
1034    config_set_program_name(&config);
1035    init_from_config_clear(&config);
1036
1037    rt_preconfig = &_PyRuntime.preconfig;
1038    assert(rt_preconfig->isolated == 1);
1039    assert(rt_preconfig->use_environment == 0);
1040
1041    dump_config();
1042    Py_Finalize();
1043    return 0;
1044}
1045
1046
1047static int test_preinit_isolated_config(void)
1048{
1049    return check_preinit_isolated_config(1);
1050}
1051
1052
1053static int test_init_isolated_config(void)
1054{
1055    return check_preinit_isolated_config(0);
1056}
1057
1058
1059static int check_init_python_config(int preinit)
1060{
1061    /* global configuration variables must be ignored */
1062    set_all_global_config_variables();
1063    Py_IsolatedFlag = 1;
1064    Py_IgnoreEnvironmentFlag = 1;
1065    Py_FrozenFlag = 1;
1066    Py_UnbufferedStdioFlag = 1;
1067    Py_NoSiteFlag = 1;
1068    Py_DontWriteBytecodeFlag = 1;
1069    Py_NoUserSiteDirectory = 1;
1070#ifdef MS_WINDOWS
1071    Py_LegacyWindowsStdioFlag = 1;
1072#endif
1073
1074    if (preinit) {
1075        PyPreConfig preconfig;
1076        PyPreConfig_InitPythonConfig(&preconfig);
1077
1078        PyStatus status = Py_PreInitialize(&preconfig);
1079        if (PyStatus_Exception(status)) {
1080            Py_ExitStatusException(status);
1081        }
1082    }
1083
1084    PyConfig config;
1085    PyConfig_InitPythonConfig(&config);
1086
1087    config_set_program_name(&config);
1088    init_from_config_clear(&config);
1089
1090    dump_config();
1091    Py_Finalize();
1092    return 0;
1093}
1094
1095
1096static int test_preinit_python_config(void)
1097{
1098    return check_init_python_config(1);
1099}
1100
1101
1102static int test_init_python_config(void)
1103{
1104    return check_init_python_config(0);
1105}
1106
1107
1108static int test_init_dont_configure_locale(void)
1109{
1110    PyPreConfig preconfig;
1111    PyPreConfig_InitPythonConfig(&preconfig);
1112
1113    preconfig.configure_locale = 0;
1114    preconfig.coerce_c_locale = 1;
1115    preconfig.coerce_c_locale_warn = 1;
1116
1117    PyStatus status = Py_PreInitialize(&preconfig);
1118    if (PyStatus_Exception(status)) {
1119        Py_ExitStatusException(status);
1120    }
1121
1122    PyConfig config;
1123    PyConfig_InitPythonConfig(&config);
1124
1125    config_set_program_name(&config);
1126    init_from_config_clear(&config);
1127
1128    dump_config();
1129    Py_Finalize();
1130    return 0;
1131}
1132
1133
1134static int test_init_dev_mode(void)
1135{
1136    PyConfig config;
1137    PyConfig_InitPythonConfig(&config);
1138
1139    putenv("PYTHONFAULTHANDLER=");
1140    putenv("PYTHONMALLOC=");
1141    config.dev_mode = 1;
1142    config_set_program_name(&config);
1143    init_from_config_clear(&config);
1144
1145    dump_config();
1146    Py_Finalize();
1147    return 0;
1148}
1149
1150static PyObject *_open_code_hook(PyObject *path, void *data)
1151{
1152    if (PyUnicode_CompareWithASCIIString(path, "$$test-filename") == 0) {
1153        return PyLong_FromVoidPtr(data);
1154    }
1155    PyObject *io = PyImport_ImportModule("_io");
1156    if (!io) {
1157        return NULL;
1158    }
1159    return PyObject_CallMethod(io, "open", "Os", path, "rb");
1160}
1161
1162static int test_open_code_hook(void)
1163{
1164    int result = 0;
1165
1166    /* Provide a hook */
1167    result = PyFile_SetOpenCodeHook(_open_code_hook, &result);
1168    if (result) {
1169        printf("Failed to set hook\n");
1170        return 1;
1171    }
1172    /* A second hook should fail */
1173    result = PyFile_SetOpenCodeHook(_open_code_hook, &result);
1174    if (!result) {
1175        printf("Should have failed to set second hook\n");
1176        return 2;
1177    }
1178
1179    Py_IgnoreEnvironmentFlag = 0;
1180    _testembed_Py_InitializeFromConfig();
1181    result = 0;
1182
1183    PyObject *r = PyFile_OpenCode("$$test-filename");
1184    if (!r) {
1185        PyErr_Print();
1186        result = 3;
1187    } else {
1188        void *cmp = PyLong_AsVoidPtr(r);
1189        Py_DECREF(r);
1190        if (cmp != &result) {
1191            printf("Did not get expected result from hook\n");
1192            result = 4;
1193        }
1194    }
1195
1196    if (!result) {
1197        PyObject *io = PyImport_ImportModule("_io");
1198        PyObject *r = io
1199            ? PyObject_CallMethod(io, "open_code", "s", "$$test-filename")
1200            : NULL;
1201        if (!r) {
1202            PyErr_Print();
1203            result = 5;
1204        } else {
1205            void *cmp = PyLong_AsVoidPtr(r);
1206            Py_DECREF(r);
1207            if (cmp != &result) {
1208                printf("Did not get expected result from hook\n");
1209                result = 6;
1210            }
1211        }
1212        Py_XDECREF(io);
1213    }
1214
1215    Py_Finalize();
1216    return result;
1217}
1218
1219static int _audit_hook_clear_count = 0;
1220
1221static int _audit_hook(const char *event, PyObject *args, void *userdata)
1222{
1223    assert(args && PyTuple_CheckExact(args));
1224    if (strcmp(event, "_testembed.raise") == 0) {
1225        PyErr_SetString(PyExc_RuntimeError, "Intentional error");
1226        return -1;
1227    } else if (strcmp(event, "_testembed.set") == 0) {
1228        if (!PyArg_ParseTuple(args, "n", userdata)) {
1229            return -1;
1230        }
1231        return 0;
1232    } else if (strcmp(event, "cpython._PySys_ClearAuditHooks") == 0) {
1233        _audit_hook_clear_count += 1;
1234    }
1235    return 0;
1236}
1237
1238static int _test_audit(Py_ssize_t setValue)
1239{
1240    Py_ssize_t sawSet = 0;
1241
1242    Py_IgnoreEnvironmentFlag = 0;
1243    PySys_AddAuditHook(_audit_hook, &sawSet);
1244    _testembed_Py_InitializeFromConfig();
1245
1246    if (PySys_Audit("_testembed.raise", NULL) == 0) {
1247        printf("No error raised");
1248        return 1;
1249    }
1250    if (PySys_Audit("_testembed.nop", NULL) != 0) {
1251        printf("Nop event failed");
1252        /* Exception from above may still remain */
1253        PyErr_Clear();
1254        return 2;
1255    }
1256    if (!PyErr_Occurred()) {
1257        printf("Exception not preserved");
1258        return 3;
1259    }
1260    PyErr_Clear();
1261
1262    if (PySys_Audit("_testembed.set", "n", setValue) != 0) {
1263        PyErr_Print();
1264        printf("Set event failed");
1265        return 4;
1266    }
1267
1268    if (sawSet != 42) {
1269        printf("Failed to see *userData change\n");
1270        return 5;
1271    }
1272    return 0;
1273}
1274
1275static int test_audit(void)
1276{
1277    int result = _test_audit(42);
1278    Py_Finalize();
1279    if (_audit_hook_clear_count != 1) {
1280        return 0x1000 | _audit_hook_clear_count;
1281    }
1282    return result;
1283}
1284
1285static volatile int _audit_subinterpreter_interpreter_count = 0;
1286
1287static int _audit_subinterpreter_hook(const char *event, PyObject *args, void *userdata)
1288{
1289    printf("%s\n", event);
1290    if (strcmp(event, "cpython.PyInterpreterState_New") == 0) {
1291        _audit_subinterpreter_interpreter_count += 1;
1292    }
1293    return 0;
1294}
1295
1296static int test_audit_subinterpreter(void)
1297{
1298    Py_IgnoreEnvironmentFlag = 0;
1299    PySys_AddAuditHook(_audit_subinterpreter_hook, NULL);
1300    _testembed_Py_InitializeFromConfig();
1301
1302    Py_NewInterpreter();
1303    Py_NewInterpreter();
1304    Py_NewInterpreter();
1305
1306    Py_Finalize();
1307
1308    switch (_audit_subinterpreter_interpreter_count) {
1309        case 3: return 0;
1310        case 0: return -1;
1311        default: return _audit_subinterpreter_interpreter_count;
1312    }
1313}
1314
1315typedef struct {
1316    const char* expected;
1317    int exit;
1318} AuditRunCommandTest;
1319
1320static int _audit_hook_run(const char *eventName, PyObject *args, void *userData)
1321{
1322    AuditRunCommandTest *test = (AuditRunCommandTest*)userData;
1323    if (strcmp(eventName, test->expected)) {
1324        return 0;
1325    }
1326
1327    if (test->exit) {
1328        PyObject *msg = PyUnicode_FromFormat("detected %s(%R)", eventName, args);
1329        if (msg) {
1330            printf("%s\n", PyUnicode_AsUTF8(msg));
1331            Py_DECREF(msg);
1332        }
1333        exit(test->exit);
1334    }
1335
1336    PyErr_Format(PyExc_RuntimeError, "detected %s(%R)", eventName, args);
1337    return -1;
1338}
1339
1340static int test_audit_run_command(void)
1341{
1342    AuditRunCommandTest test = {"cpython.run_command"};
1343    wchar_t *argv[] = {PROGRAM_NAME, L"-c", L"pass"};
1344
1345    Py_IgnoreEnvironmentFlag = 0;
1346    PySys_AddAuditHook(_audit_hook_run, (void*)&test);
1347
1348    return Py_Main(Py_ARRAY_LENGTH(argv), argv);
1349}
1350
1351static int test_audit_run_file(void)
1352{
1353    AuditRunCommandTest test = {"cpython.run_file"};
1354    wchar_t *argv[] = {PROGRAM_NAME, L"filename.py"};
1355
1356    Py_IgnoreEnvironmentFlag = 0;
1357    PySys_AddAuditHook(_audit_hook_run, (void*)&test);
1358
1359    return Py_Main(Py_ARRAY_LENGTH(argv), argv);
1360}
1361
1362static int run_audit_run_test(int argc, wchar_t **argv, void *test)
1363{
1364    PyConfig config;
1365    PyConfig_InitPythonConfig(&config);
1366
1367    config.argv.length = argc;
1368    config.argv.items = argv;
1369    config.parse_argv = 1;
1370    config.program_name = argv[0];
1371    config.interactive = 1;
1372    config.isolated = 0;
1373    config.use_environment = 1;
1374    config.quiet = 1;
1375
1376    PySys_AddAuditHook(_audit_hook_run, test);
1377
1378    PyStatus status = Py_InitializeFromConfig(&config);
1379    if (PyStatus_Exception(status)) {
1380        Py_ExitStatusException(status);
1381    }
1382
1383    return Py_RunMain();
1384}
1385
1386static int test_audit_run_interactivehook(void)
1387{
1388    AuditRunCommandTest test = {"cpython.run_interactivehook", 10};
1389    wchar_t *argv[] = {PROGRAM_NAME};
1390    return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test);
1391}
1392
1393static int test_audit_run_startup(void)
1394{
1395    AuditRunCommandTest test = {"cpython.run_startup", 10};
1396    wchar_t *argv[] = {PROGRAM_NAME};
1397    return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test);
1398}
1399
1400static int test_audit_run_stdin(void)
1401{
1402    AuditRunCommandTest test = {"cpython.run_stdin"};
1403    wchar_t *argv[] = {PROGRAM_NAME};
1404    return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test);
1405}
1406
1407static int test_init_read_set(void)
1408{
1409    PyStatus status;
1410    PyConfig config;
1411    PyConfig_InitPythonConfig(&config);
1412
1413    status = PyConfig_SetBytesString(&config, &config.program_name,
1414                                     "./init_read_set");
1415    if (PyStatus_Exception(status)) {
1416        goto fail;
1417    }
1418
1419    status = PyConfig_Read(&config);
1420    if (PyStatus_Exception(status)) {
1421        goto fail;
1422    }
1423
1424    status = PyWideStringList_Insert(&config.module_search_paths,
1425                                     1, L"test_path_insert1");
1426    if (PyStatus_Exception(status)) {
1427        goto fail;
1428    }
1429
1430    status = PyWideStringList_Append(&config.module_search_paths,
1431                                     L"test_path_append");
1432    if (PyStatus_Exception(status)) {
1433        goto fail;
1434    }
1435
1436    /* override executable computed by PyConfig_Read() */
1437    config_set_string(&config, &config.executable, L"my_executable");
1438    init_from_config_clear(&config);
1439
1440    dump_config();
1441    Py_Finalize();
1442    return 0;
1443
1444fail:
1445    PyConfig_Clear(&config);
1446    Py_ExitStatusException(status);
1447}
1448
1449
1450static int test_init_sys_add(void)
1451{
1452    PySys_AddXOption(L"sysadd_xoption");
1453    PySys_AddXOption(L"faulthandler");
1454    PySys_AddWarnOption(L"ignore:::sysadd_warnoption");
1455
1456    PyConfig config;
1457    PyConfig_InitPythonConfig(&config);
1458
1459    wchar_t* argv[] = {
1460        L"python3",
1461        L"-W",
1462        L"ignore:::cmdline_warnoption",
1463        L"-X",
1464        L"cmdline_xoption",
1465    };
1466    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
1467    config.parse_argv = 1;
1468
1469    PyStatus status;
1470    status = PyWideStringList_Append(&config.xoptions,
1471                                     L"config_xoption");
1472    if (PyStatus_Exception(status)) {
1473        goto fail;
1474    }
1475
1476    status = PyWideStringList_Append(&config.warnoptions,
1477                                     L"ignore:::config_warnoption");
1478    if (PyStatus_Exception(status)) {
1479        goto fail;
1480    }
1481
1482    config_set_program_name(&config);
1483    init_from_config_clear(&config);
1484
1485    dump_config();
1486    Py_Finalize();
1487    return 0;
1488
1489fail:
1490    PyConfig_Clear(&config);
1491    Py_ExitStatusException(status);
1492}
1493
1494
1495static int test_init_setpath(void)
1496{
1497    char *env = getenv("TESTPATH");
1498    if (!env) {
1499        error("missing TESTPATH env var");
1500        return 1;
1501    }
1502    wchar_t *path = Py_DecodeLocale(env, NULL);
1503    if (path == NULL) {
1504        error("failed to decode TESTPATH");
1505        return 1;
1506    }
1507    Py_SetPath(path);
1508    PyMem_RawFree(path);
1509    putenv("TESTPATH=");
1510
1511    Py_Initialize();
1512    dump_config();
1513    Py_Finalize();
1514    return 0;
1515}
1516
1517
1518static int test_init_setpath_config(void)
1519{
1520    PyPreConfig preconfig;
1521    PyPreConfig_InitPythonConfig(&preconfig);
1522
1523    /* Explicitly preinitializes with Python preconfiguration to avoid
1524      Py_SetPath() implicit preinitialization with compat preconfiguration. */
1525    PyStatus status = Py_PreInitialize(&preconfig);
1526    if (PyStatus_Exception(status)) {
1527        Py_ExitStatusException(status);
1528    }
1529
1530    char *env = getenv("TESTPATH");
1531    if (!env) {
1532        error("missing TESTPATH env var");
1533        return 1;
1534    }
1535    wchar_t *path = Py_DecodeLocale(env, NULL);
1536    if (path == NULL) {
1537        error("failed to decode TESTPATH");
1538        return 1;
1539    }
1540    Py_SetPath(path);
1541    PyMem_RawFree(path);
1542    putenv("TESTPATH=");
1543
1544    PyConfig config;
1545    PyConfig_InitPythonConfig(&config);
1546
1547    config_set_string(&config, &config.program_name, L"conf_program_name");
1548    config_set_string(&config, &config.executable, L"conf_executable");
1549    init_from_config_clear(&config);
1550
1551    dump_config();
1552    Py_Finalize();
1553    return 0;
1554}
1555
1556
1557static int test_init_setpythonhome(void)
1558{
1559    char *env = getenv("TESTHOME");
1560    if (!env) {
1561        error("missing TESTHOME env var");
1562        return 1;
1563    }
1564    wchar_t *home = Py_DecodeLocale(env, NULL);
1565    if (home == NULL) {
1566        error("failed to decode TESTHOME");
1567        return 1;
1568    }
1569    Py_SetPythonHome(home);
1570    PyMem_RawFree(home);
1571    putenv("TESTHOME=");
1572
1573    Py_Initialize();
1574    dump_config();
1575    Py_Finalize();
1576    return 0;
1577}
1578
1579
1580static int test_init_is_python_build(void)
1581{
1582    // gh-91985: in-tree builds fail to check for build directory landmarks
1583    // under the effect of 'home' or PYTHONHOME environment variable.
1584    char *env = getenv("TESTHOME");
1585    if (!env) {
1586        error("missing TESTHOME env var");
1587        return 1;
1588    }
1589    wchar_t *home = Py_DecodeLocale(env, NULL);
1590    if (home == NULL) {
1591        error("failed to decode TESTHOME");
1592        return 1;
1593    }
1594
1595    PyConfig config;
1596    _PyConfig_InitCompatConfig(&config);
1597    config_set_program_name(&config);
1598    config_set_string(&config, &config.home, home);
1599    PyMem_RawFree(home);
1600    putenv("TESTHOME=");
1601
1602    // Use an impossible value so we can detect whether it isn't updated
1603    // during initialization.
1604    config._is_python_build = INT_MAX;
1605    env = getenv("NEGATIVE_ISPYTHONBUILD");
1606    if (env && strcmp(env, "0") != 0) {
1607        config._is_python_build = INT_MIN;
1608    }
1609    init_from_config_clear(&config);
1610    Py_Finalize();
1611    // Second initialization
1612    config._is_python_build = -1;
1613    init_from_config_clear(&config);
1614    dump_config();  // home and _is_python_build are cached in _Py_path_config
1615    Py_Finalize();
1616    return 0;
1617}
1618
1619
1620static int test_init_warnoptions(void)
1621{
1622    putenv("PYTHONWARNINGS=ignore:::env1,ignore:::env2");
1623
1624    PySys_AddWarnOption(L"ignore:::PySys_AddWarnOption1");
1625    PySys_AddWarnOption(L"ignore:::PySys_AddWarnOption2");
1626
1627    PyConfig config;
1628    PyConfig_InitPythonConfig(&config);
1629
1630    config.dev_mode = 1;
1631    config.bytes_warning = 1;
1632
1633    config_set_program_name(&config);
1634
1635    PyStatus status;
1636    status = PyWideStringList_Append(&config.warnoptions,
1637                                     L"ignore:::PyConfig_BeforeRead");
1638    if (PyStatus_Exception(status)) {
1639        Py_ExitStatusException(status);
1640    }
1641
1642    wchar_t* argv[] = {
1643        L"python3",
1644        L"-Wignore:::cmdline1",
1645        L"-Wignore:::cmdline2"};
1646    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
1647    config.parse_argv = 1;
1648
1649    status = PyConfig_Read(&config);
1650    if (PyStatus_Exception(status)) {
1651        Py_ExitStatusException(status);
1652    }
1653
1654    status = PyWideStringList_Append(&config.warnoptions,
1655                                     L"ignore:::PyConfig_AfterRead");
1656    if (PyStatus_Exception(status)) {
1657        Py_ExitStatusException(status);
1658    }
1659
1660    status = PyWideStringList_Insert(&config.warnoptions,
1661                                     0, L"ignore:::PyConfig_Insert0");
1662    if (PyStatus_Exception(status)) {
1663        Py_ExitStatusException(status);
1664    }
1665
1666    init_from_config_clear(&config);
1667    dump_config();
1668    Py_Finalize();
1669    return 0;
1670}
1671
1672
1673static int tune_config(void)
1674{
1675    PyConfig config;
1676    PyConfig_InitPythonConfig(&config);
1677    if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
1678        PyConfig_Clear(&config);
1679        PyErr_Print();
1680        return -1;
1681    }
1682
1683    config.bytes_warning = 2;
1684
1685    if (_PyInterpreterState_SetConfig(&config) < 0) {
1686        PyConfig_Clear(&config);
1687        return -1;
1688    }
1689    PyConfig_Clear(&config);
1690    return 0;
1691}
1692
1693
1694static int test_init_set_config(void)
1695{
1696    // Initialize core
1697    PyConfig config;
1698    PyConfig_InitIsolatedConfig(&config);
1699    config_set_string(&config, &config.program_name, PROGRAM_NAME);
1700    config._init_main = 0;
1701    config.bytes_warning = 0;
1702    init_from_config_clear(&config);
1703
1704    // Tune the configuration using _PyInterpreterState_SetConfig()
1705    if (tune_config() < 0) {
1706        PyErr_Print();
1707        return 1;
1708    }
1709
1710    // Finish initialization: main part
1711    PyStatus status = _Py_InitializeMain();
1712    if (PyStatus_Exception(status)) {
1713        Py_ExitStatusException(status);
1714    }
1715
1716    dump_config();
1717    Py_Finalize();
1718    return 0;
1719}
1720
1721
1722static void configure_init_main(PyConfig *config)
1723{
1724    wchar_t* argv[] = {
1725        L"python3", L"-c",
1726        (L"import _testinternalcapi, json; "
1727         L"print(json.dumps(_testinternalcapi.get_configs()))"),
1728        L"arg2"};
1729
1730    config->parse_argv = 1;
1731
1732    config_set_argv(config, Py_ARRAY_LENGTH(argv), argv);
1733    config_set_string(config, &config->program_name, L"./python3");
1734}
1735
1736
1737static int test_init_run_main(void)
1738{
1739    PyConfig config;
1740    PyConfig_InitPythonConfig(&config);
1741
1742    configure_init_main(&config);
1743    init_from_config_clear(&config);
1744
1745    return Py_RunMain();
1746}
1747
1748
1749static int test_init_main(void)
1750{
1751    PyConfig config;
1752    PyConfig_InitPythonConfig(&config);
1753
1754    configure_init_main(&config);
1755    config._init_main = 0;
1756    init_from_config_clear(&config);
1757
1758    /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
1759    int res = PyRun_SimpleString(
1760        "import sys; "
1761        "print('Run Python code before _Py_InitializeMain', "
1762               "file=sys.stderr)");
1763    if (res < 0) {
1764        exit(1);
1765    }
1766
1767    PyStatus status = _Py_InitializeMain();
1768    if (PyStatus_Exception(status)) {
1769        Py_ExitStatusException(status);
1770    }
1771
1772    return Py_RunMain();
1773}
1774
1775
1776static int test_run_main(void)
1777{
1778    PyConfig config;
1779    PyConfig_InitPythonConfig(&config);
1780
1781    wchar_t *argv[] = {L"python3", L"-c",
1782                       (L"import sys; "
1783                        L"print(f'Py_RunMain(): sys.argv={sys.argv}')"),
1784                       L"arg2"};
1785    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
1786    config_set_string(&config, &config.program_name, L"./python3");
1787    init_from_config_clear(&config);
1788
1789    return Py_RunMain();
1790}
1791
1792
1793static int test_run_main_loop(void)
1794{
1795    // bpo-40413: Calling Py_InitializeFromConfig()+Py_RunMain() multiple
1796    // times must not crash.
1797    for (int i=0; i<5; i++) {
1798        int exitcode = test_run_main();
1799        if (exitcode != 0) {
1800            return exitcode;
1801        }
1802    }
1803    return 0;
1804}
1805
1806
1807static int test_get_argc_argv(void)
1808{
1809    PyConfig config;
1810    PyConfig_InitPythonConfig(&config);
1811
1812    wchar_t *argv[] = {L"python3", L"-c", L"pass", L"arg2"};
1813    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
1814    config_set_string(&config, &config.program_name, L"./python3");
1815
1816    // Calling PyConfig_Read() twice must not change Py_GetArgcArgv() result.
1817    // The second call is done by Py_InitializeFromConfig().
1818    PyStatus status = PyConfig_Read(&config);
1819    if (PyStatus_Exception(status)) {
1820        PyConfig_Clear(&config);
1821        Py_ExitStatusException(status);
1822    }
1823
1824    init_from_config_clear(&config);
1825
1826    int get_argc;
1827    wchar_t **get_argv;
1828    Py_GetArgcArgv(&get_argc, &get_argv);
1829    printf("argc: %i\n", get_argc);
1830    assert(get_argc == Py_ARRAY_LENGTH(argv));
1831    for (int i=0; i < get_argc; i++) {
1832        printf("argv[%i]: %ls\n", i, get_argv[i]);
1833        assert(wcscmp(get_argv[i], argv[i]) == 0);
1834    }
1835
1836    Py_Finalize();
1837
1838    printf("\n");
1839    printf("test ok\n");
1840    return 0;
1841}
1842
1843
1844static int check_use_frozen_modules(const char *rawval)
1845{
1846    wchar_t optval[100];
1847    if (rawval == NULL) {
1848        wcscpy(optval, L"frozen_modules");
1849    }
1850    else if (swprintf(optval, 100,
1851#if defined(_MSC_VER)
1852        L"frozen_modules=%S",
1853#else
1854        L"frozen_modules=%s",
1855#endif
1856        rawval) < 0) {
1857        error("rawval is too long");
1858        return -1;
1859    }
1860
1861    PyConfig config;
1862    PyConfig_InitPythonConfig(&config);
1863
1864    config.parse_argv = 1;
1865
1866    wchar_t* argv[] = {
1867        L"./argv0",
1868        L"-X",
1869        optval,
1870        L"-c",
1871        L"pass",
1872    };
1873    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
1874    init_from_config_clear(&config);
1875
1876    dump_config();
1877    Py_Finalize();
1878    return 0;
1879}
1880
1881static int test_init_use_frozen_modules(void)
1882{
1883    const char *envvar = getenv("TESTFROZEN");
1884    return check_use_frozen_modules(envvar);
1885}
1886
1887
1888static int test_unicode_id_init(void)
1889{
1890    // bpo-42882: Test that _PyUnicode_FromId() works
1891    // when Python is initialized multiples times.
1892    _Py_IDENTIFIER(test_unicode_id_init);
1893
1894    // Initialize Python once without using the identifier
1895    _testembed_Py_InitializeFromConfig();
1896    Py_Finalize();
1897
1898    // Now initialize Python multiple times and use the identifier.
1899    // The first _PyUnicode_FromId() call initializes the identifier index.
1900    for (int i=0; i<3; i++) {
1901        _testembed_Py_InitializeFromConfig();
1902
1903        PyObject *str1, *str2;
1904
1905        str1 = _PyUnicode_FromId(&PyId_test_unicode_id_init);
1906        assert(str1 != NULL);
1907        assert(Py_REFCNT(str1) == 1);
1908
1909        str2 = PyUnicode_FromString("test_unicode_id_init");
1910        assert(str2 != NULL);
1911
1912        assert(PyUnicode_Compare(str1, str2) == 0);
1913
1914        // str1 is a borrowed reference
1915        Py_DECREF(str2);
1916
1917        Py_Finalize();
1918    }
1919    return 0;
1920}
1921
1922
1923#ifndef MS_WINDOWS
1924#include "test_frozenmain.h"      // M_test_frozenmain
1925
1926static int test_frozenmain(void)
1927{
1928    static struct _frozen frozen_modules[4] = {
1929        {"__main__", M_test_frozenmain, sizeof(M_test_frozenmain)},
1930        {0, 0, 0}   // sentinel
1931    };
1932
1933    char* argv[] = {
1934        "./argv0",
1935        "-E",
1936        "arg1",
1937        "arg2",
1938    };
1939    PyImport_FrozenModules = frozen_modules;
1940    return Py_FrozenMain(Py_ARRAY_LENGTH(argv), argv);
1941}
1942#endif  // !MS_WINDOWS
1943
1944static int test_repeated_init_and_inittab(void)
1945{
1946    // bpo-44441: Py_RunMain() must reset PyImport_Inittab at exit.
1947    // It must be possible to call PyImport_AppendInittab() or
1948    // PyImport_ExtendInittab() before each Python initialization.
1949    for (int i=1; i <= INIT_LOOPS; i++) {
1950        printf("--- Pass %d ---\n", i);
1951
1952        // Call PyImport_AppendInittab() at each iteration
1953        if (PyImport_AppendInittab(EMBEDDED_EXT_NAME,
1954                                   &PyInit_embedded_ext) != 0) {
1955            fprintf(stderr, "PyImport_AppendInittab() failed\n");
1956            return 1;
1957        }
1958
1959        // Initialize Python
1960        wchar_t* argv[] = {PROGRAM_NAME, L"-c", L"pass"};
1961        PyConfig config;
1962        PyConfig_InitPythonConfig(&config);
1963        config.isolated = 1;
1964        config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
1965        init_from_config_clear(&config);
1966
1967        // Py_RunMain() calls _PyImport_Fini2() which resets PyImport_Inittab
1968        int exitcode = Py_RunMain();
1969        if (exitcode != 0) {
1970            return exitcode;
1971        }
1972    }
1973    return 0;
1974}
1975
1976static void wrap_allocator(PyMemAllocatorEx *allocator);
1977static void unwrap_allocator(PyMemAllocatorEx *allocator);
1978
1979static void *
1980malloc_wrapper(void *ctx, size_t size)
1981{
1982    PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
1983    unwrap_allocator(allocator);
1984    PyEval_GetFrame();  // BOOM!
1985    wrap_allocator(allocator);
1986    return allocator->malloc(allocator->ctx, size);
1987}
1988
1989static void *
1990calloc_wrapper(void *ctx, size_t nelem, size_t elsize)
1991{
1992    PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
1993    return allocator->calloc(allocator->ctx, nelem, elsize);
1994}
1995
1996static void *
1997realloc_wrapper(void *ctx, void *ptr, size_t new_size)
1998{
1999    PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
2000    return allocator->realloc(allocator->ctx, ptr, new_size);
2001}
2002
2003static void
2004free_wrapper(void *ctx, void *ptr)
2005{
2006    PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
2007    allocator->free(allocator->ctx, ptr);
2008}
2009
2010static void
2011wrap_allocator(PyMemAllocatorEx *allocator)
2012{
2013    PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, allocator);
2014    PyMemAllocatorEx wrapper = {
2015        .malloc = &malloc_wrapper,
2016        .calloc = &calloc_wrapper,
2017        .realloc = &realloc_wrapper,
2018        .free = &free_wrapper,
2019        .ctx = allocator,
2020    };
2021    PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &wrapper);
2022}
2023
2024static void
2025unwrap_allocator(PyMemAllocatorEx *allocator)
2026{
2027    PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, allocator);
2028}
2029
2030static int
2031test_get_incomplete_frame(void)
2032{
2033    _testembed_Py_InitializeFromConfig();
2034    PyMemAllocatorEx allocator;
2035    wrap_allocator(&allocator);
2036    // Force an allocation with an incomplete (generator) frame:
2037    int result = PyRun_SimpleString("(_ for _ in ())");
2038    unwrap_allocator(&allocator);
2039    Py_Finalize();
2040    return result;
2041}
2042
2043
2044/* *********************************************************
2045 * List of test cases and the function that implements it.
2046 *
2047 * Names are compared case-sensitively with the first
2048 * argument. If no match is found, or no first argument was
2049 * provided, the names of all test cases are printed and
2050 * the exit code will be -1.
2051 *
2052 * The int returned from test functions is used as the exit
2053 * code, and test_capi treats all non-zero exit codes as a
2054 * failed test.
2055 *********************************************************/
2056struct TestCase
2057{
2058    const char *name;
2059    int (*func)(void);
2060};
2061
2062static struct TestCase TestCases[] = {
2063    // Python initialization
2064    {"test_repeated_init_exec", test_repeated_init_exec},
2065    {"test_repeated_simple_init", test_repeated_simple_init},
2066    {"test_forced_io_encoding", test_forced_io_encoding},
2067    {"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters},
2068    {"test_repeated_init_and_inittab", test_repeated_init_and_inittab},
2069    {"test_pre_initialization_api", test_pre_initialization_api},
2070    {"test_pre_initialization_sys_options", test_pre_initialization_sys_options},
2071    {"test_bpo20891", test_bpo20891},
2072    {"test_initialize_twice", test_initialize_twice},
2073    {"test_initialize_pymain", test_initialize_pymain},
2074    {"test_init_initialize_config", test_init_initialize_config},
2075    {"test_preinit_compat_config", test_preinit_compat_config},
2076    {"test_init_compat_config", test_init_compat_config},
2077    {"test_init_global_config", test_init_global_config},
2078    {"test_init_from_config", test_init_from_config},
2079    {"test_init_parse_argv", test_init_parse_argv},
2080    {"test_init_dont_parse_argv", test_init_dont_parse_argv},
2081    {"test_init_compat_env", test_init_compat_env},
2082    {"test_init_python_env", test_init_python_env},
2083    {"test_init_env_dev_mode", test_init_env_dev_mode},
2084    {"test_init_env_dev_mode_alloc", test_init_env_dev_mode_alloc},
2085    {"test_init_dont_configure_locale", test_init_dont_configure_locale},
2086    {"test_init_dev_mode", test_init_dev_mode},
2087    {"test_init_isolated_flag", test_init_isolated_flag},
2088    {"test_preinit_isolated_config", test_preinit_isolated_config},
2089    {"test_init_isolated_config", test_init_isolated_config},
2090    {"test_preinit_python_config", test_preinit_python_config},
2091    {"test_init_python_config", test_init_python_config},
2092    {"test_preinit_isolated1", test_preinit_isolated1},
2093    {"test_preinit_isolated2", test_preinit_isolated2},
2094    {"test_preinit_parse_argv", test_preinit_parse_argv},
2095    {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv},
2096    {"test_init_read_set", test_init_read_set},
2097    {"test_init_run_main", test_init_run_main},
2098    {"test_init_main", test_init_main},
2099    {"test_init_sys_add", test_init_sys_add},
2100    {"test_init_setpath", test_init_setpath},
2101    {"test_init_setpath_config", test_init_setpath_config},
2102    {"test_init_setpythonhome", test_init_setpythonhome},
2103    {"test_init_is_python_build", test_init_is_python_build},
2104    {"test_init_warnoptions", test_init_warnoptions},
2105    {"test_init_set_config", test_init_set_config},
2106    {"test_run_main", test_run_main},
2107    {"test_run_main_loop", test_run_main_loop},
2108    {"test_get_argc_argv", test_get_argc_argv},
2109    {"test_init_use_frozen_modules", test_init_use_frozen_modules},
2110
2111    // Audit
2112    {"test_open_code_hook", test_open_code_hook},
2113    {"test_audit", test_audit},
2114    {"test_audit_subinterpreter", test_audit_subinterpreter},
2115    {"test_audit_run_command", test_audit_run_command},
2116    {"test_audit_run_file", test_audit_run_file},
2117    {"test_audit_run_interactivehook", test_audit_run_interactivehook},
2118    {"test_audit_run_startup", test_audit_run_startup},
2119    {"test_audit_run_stdin", test_audit_run_stdin},
2120
2121    // Specific C API
2122    {"test_unicode_id_init", test_unicode_id_init},
2123#ifndef MS_WINDOWS
2124    {"test_frozenmain", test_frozenmain},
2125#endif
2126    {"test_get_incomplete_frame", test_get_incomplete_frame},
2127
2128    {NULL, NULL}
2129};
2130
2131
2132int main(int argc, char *argv[])
2133{
2134    main_argc = argc;
2135    main_argv = argv;
2136
2137    if (argc > 1) {
2138        for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
2139            if (strcmp(argv[1], tc->name) == 0)
2140                return (*tc->func)();
2141        }
2142    }
2143
2144    /* No match found, or no test name provided, so display usage */
2145    printf("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"
2146           "Normally executed via 'EmbeddingTests' in Lib/test/test_embed.py\n\n"
2147           "Usage: %s TESTNAME\n\nAll available tests:\n", argv[0]);
2148    for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
2149        printf("  %s\n", tc->name);
2150    }
2151
2152    /* Non-zero exit code will cause test_embed.py tests to fail.
2153       This is intentional. */
2154    return -1;
2155}
2156