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