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 
19 int main_argc;
20 char **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 
error(const char * msg)42 static void error(const char *msg)
43 {
44     fprintf(stderr, "ERROR: %s\n", msg);
45     fflush(stderr);
46 }
47 
48 
config_set_string(PyConfig * config,wchar_t ** config_str,const wchar_t * str)49 static 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 
config_set_program_name(PyConfig * config)59 static 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 
init_from_config_clear(PyConfig * config)66 static 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 
_testembed_Py_InitializeFromConfig(void)76 static 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 
_testembed_Py_Initialize(void)84 static 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 
print_subinterp(void)95 static 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 
test_repeated_init_and_subinterpreters(void)112 static 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 
146 static PyModuleDef embedded_ext = {
147     PyModuleDef_HEAD_INIT,
148     .m_name = EMBEDDED_EXT_NAME,
149     .m_size = 0,
150 };
151 
152 static PyObject*
PyInit_embedded_ext(void)153 PyInit_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.
test_repeated_init_exec(void)165 static 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)
test_repeated_simple_init(void)191 static 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 
check_stdio_details(const char * encoding,const char * errors)209 static 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 
test_forced_io_encoding(void)236 static 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 
test_pre_initialization_api(void)268 static 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 */
test_pre_initialization_sys_options(void)298 static 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 */
bpo20891_thread(void * lockp)350 static 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 
test_bpo20891(void)365 static 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 
test_initialize_twice(void)399 static 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 
test_initialize_pymain(void)412 static 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 
430 static void
dump_config(void)431 dump_config(void)
432 {
433     (void) PyRun_SimpleStringFlags(
434         "import _testinternalcapi, json; "
435         "print(json.dumps(_testinternalcapi.get_configs()))",
436         0);
437 }
438 
439 
test_init_initialize_config(void)440 static int test_init_initialize_config(void)
441 {
442     _testembed_Py_InitializeFromConfig();
443     dump_config();
444     Py_Finalize();
445     return 0;
446 }
447 
448 
config_set_argv(PyConfig * config,Py_ssize_t argc,wchar_t * const * argv)449 static 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 
459 static void
config_set_wide_string_list(PyConfig * config,PyWideStringList * list,Py_ssize_t length,wchar_t ** items)460 config_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 
check_init_compat_config(int preinit)471 static 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 
test_preinit_compat_config(void)497 static int test_preinit_compat_config(void)
498 {
499     return check_init_compat_config(1);
500 }
501 
502 
test_init_compat_config(void)503 static int test_init_compat_config(void)
504 {
505     return check_init_compat_config(0);
506 }
507 
508 
test_init_global_config(void)509 static 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 
test_init_from_config(void)558 static 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 
check_init_parse_argv(int parse_argv)717 static 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 
test_init_parse_argv(void)742 static int test_init_parse_argv(void)
743 {
744     return check_init_parse_argv(1);
745 }
746 
747 
test_init_dont_parse_argv(void)748 static int test_init_dont_parse_argv(void)
749 {
750     return check_init_parse_argv(0);
751 }
752 
753 
set_most_env_vars(void)754 static 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 
set_all_env_vars(void)777 static 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 
test_init_compat_env(void)786 static 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 
test_init_python_env(void)798 static 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 
set_all_env_vars_dev_mode(void)814 static void set_all_env_vars_dev_mode(void)
815 {
816     putenv("PYTHONMALLOC=");
817     putenv("PYTHONFAULTHANDLER=");
818     putenv("PYTHONDEVMODE=1");
819 }
820 
821 
test_init_env_dev_mode(void)822 static 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 
test_init_env_dev_mode_alloc(void)834 static 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 
test_init_isolated_flag(void)847 static 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 */
test_preinit_isolated1(void)871 static 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 */
test_preinit_isolated2(void)897 static 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 
test_preinit_dont_parse_argv(void)926 static 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 
test_preinit_parse_argv(void)964 static 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 
set_all_global_config_variables(void)984 static 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 
check_preinit_isolated_config(int preinit)1006 static 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 
test_preinit_isolated_config(void)1047 static int test_preinit_isolated_config(void)
1048 {
1049     return check_preinit_isolated_config(1);
1050 }
1051 
1052 
test_init_isolated_config(void)1053 static int test_init_isolated_config(void)
1054 {
1055     return check_preinit_isolated_config(0);
1056 }
1057 
1058 
check_init_python_config(int preinit)1059 static 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 
test_preinit_python_config(void)1096 static int test_preinit_python_config(void)
1097 {
1098     return check_init_python_config(1);
1099 }
1100 
1101 
test_init_python_config(void)1102 static int test_init_python_config(void)
1103 {
1104     return check_init_python_config(0);
1105 }
1106 
1107 
test_init_dont_configure_locale(void)1108 static 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 
test_init_dev_mode(void)1134 static 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 
_open_code_hook(PyObject * path,void * data)1150 static 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 
test_open_code_hook(void)1162 static 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 
1219 static int _audit_hook_clear_count = 0;
1220 
_audit_hook(const char * event,PyObject * args,void * userdata)1221 static 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 
_test_audit(Py_ssize_t setValue)1238 static 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 
test_audit(void)1275 static 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 
1285 static volatile int _audit_subinterpreter_interpreter_count = 0;
1286 
_audit_subinterpreter_hook(const char * event,PyObject * args,void * userdata)1287 static 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 
test_audit_subinterpreter(void)1296 static 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 
1315 typedef struct {
1316     const char* expected;
1317     int exit;
1318 } AuditRunCommandTest;
1319 
_audit_hook_run(const char * eventName,PyObject * args,void * userData)1320 static 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 
test_audit_run_command(void)1340 static 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 
test_audit_run_file(void)1351 static 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 
run_audit_run_test(int argc,wchar_t ** argv,void * test)1362 static 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 
test_audit_run_interactivehook(void)1386 static 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 
test_audit_run_startup(void)1393 static 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 
test_audit_run_stdin(void)1400 static 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 
test_init_read_set(void)1407 static 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 
1444 fail:
1445     PyConfig_Clear(&config);
1446     Py_ExitStatusException(status);
1447 }
1448 
1449 
test_init_sys_add(void)1450 static 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 
1489 fail:
1490     PyConfig_Clear(&config);
1491     Py_ExitStatusException(status);
1492 }
1493 
1494 
test_init_setpath(void)1495 static 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 
test_init_setpath_config(void)1518 static 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 
test_init_setpythonhome(void)1557 static 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 
test_init_is_python_build(void)1580 static 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 
test_init_warnoptions(void)1620 static 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 
tune_config(void)1673 static 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 
test_init_set_config(void)1694 static 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 
configure_init_main(PyConfig * config)1722 static 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 
test_init_run_main(void)1737 static 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 
test_init_main(void)1749 static 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 
test_run_main(void)1776 static 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 
test_run_main_loop(void)1793 static 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 
test_get_argc_argv(void)1807 static 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 
check_use_frozen_modules(const char * rawval)1844 static 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 
test_init_use_frozen_modules(void)1881 static int test_init_use_frozen_modules(void)
1882 {
1883     const char *envvar = getenv("TESTFROZEN");
1884     return check_use_frozen_modules(envvar);
1885 }
1886 
1887 
test_unicode_id_init(void)1888 static 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 
test_frozenmain(void)1926 static 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 
test_repeated_init_and_inittab(void)1944 static 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 
1976 static void wrap_allocator(PyMemAllocatorEx *allocator);
1977 static void unwrap_allocator(PyMemAllocatorEx *allocator);
1978 
1979 static void *
malloc_wrapper(void * ctx,size_t size)1980 malloc_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 
1989 static void *
calloc_wrapper(void * ctx,size_t nelem,size_t elsize)1990 calloc_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 
1996 static void *
realloc_wrapper(void * ctx,void * ptr,size_t new_size)1997 realloc_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 
2003 static void
free_wrapper(void * ctx,void * ptr)2004 free_wrapper(void *ctx, void *ptr)
2005 {
2006     PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
2007     allocator->free(allocator->ctx, ptr);
2008 }
2009 
2010 static void
wrap_allocator(PyMemAllocatorEx * allocator)2011 wrap_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 
2024 static void
unwrap_allocator(PyMemAllocatorEx * allocator)2025 unwrap_allocator(PyMemAllocatorEx *allocator)
2026 {
2027     PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, allocator);
2028 }
2029 
2030 static int
test_get_incomplete_frame(void)2031 test_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  *********************************************************/
2056 struct TestCase
2057 {
2058     const char *name;
2059     int (*func)(void);
2060 };
2061 
2062 static 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 
main(int argc,char * argv[])2132 int 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