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
28static 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
39static 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
56static 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
90static PyModuleDef embedded_ext = {
91 PyModuleDef_HEAD_INIT,
92 .m_name = EMBEDDED_EXT_NAME,
93 .m_size = 0,
94};
95
96static PyObject*
97PyInit_embedded_ext(void)
98{
99 return PyModule_Create(&embedded_ext);
100}
101
102/*****************************************************
103 * Test forcing a particular IO encoding
104 *****************************************************/
105
106static 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
133static 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
165static 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 */
195static 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 */
247static 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
264static 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
296static 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
309static 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
327static void
328dump_config(void)
329{
330 (void) PyRun_SimpleStringFlags(
331 "import _testinternalcapi, json; "
332 "print(json.dumps(_testinternalcapi.get_configs()))",
333 0);
334}
335
336
337static int test_init_initialize_config(void)
338{
339 _testembed_Py_Initialize();
340 dump_config();
341 Py_Finalize();
342 return 0;
343}
344
345
346static 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
356static 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
366static void
367config_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
378static 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
385static 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
395static 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
421static int test_preinit_compat_config(void)
422{
423 return check_init_compat_config(1);
424}
425
426
427static int test_init_compat_config(void)
428{
429 return check_init_compat_config(0);
430}
431
432
433static 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
482static 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
636static 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
661static int test_init_parse_argv(void)
662{
663 return check_init_parse_argv(1);
664}
665
666
667static int test_init_dont_parse_argv(void)
668{
669 return check_init_parse_argv(0);
670}
671
672
673static 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
694static 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
703static 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
715static 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
731static void set_all_env_vars_dev_mode(void)
732{
733 putenv("PYTHONMALLOC=");
734 putenv("PYTHONFAULTHANDLER=");
735 putenv("PYTHONDEVMODE=1");
736}
737
738
739static 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
751static 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
764static 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 */
784static 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 */
810static 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
839static 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
876static 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
896static 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
918static 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
959static int test_preinit_isolated_config(void)
960{
961 return check_preinit_isolated_config(1);
962}
963
964
965static int test_init_isolated_config(void)
966{
967 return check_preinit_isolated_config(0);
968}
969
970
971static 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
1008static int test_preinit_python_config(void)
1009{
1010 return check_init_python_config(1);
1011}
1012
1013
1014static int test_init_python_config(void)
1015{
1016 return check_init_python_config(0);
1017}
1018
1019
1020static 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
1046static 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
1062static 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
1074static 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
1131static int _audit_hook_clear_count = 0;
1132
1133static 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
1150static 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
1187static 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
1197static volatile int _audit_subinterpreter_interpreter_count = 0;
1198
1199static 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
1208static 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
1227typedef struct {
1228 const char* expected;
1229 int exit;
1230} AuditRunCommandTest;
1231
1232static 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
1252static 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
1263static 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
1274static 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
1298static 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
1305static 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
1312static 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
1319static 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
1356fail:
1357 PyConfig_Clear(&config);
1358 Py_ExitStatusException(status);
1359}
1360
1361
1362static 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
1401fail:
1402 PyConfig_Clear(&config);
1403 Py_ExitStatusException(status);
1404}
1405
1406
1407static 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
1430static 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
1469static 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
1492static 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
1545static 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
1566static 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
1594static 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
1609static 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
1621static 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
1648static 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
1665static 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
1679static 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
1716static 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.
1753static 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
1765static 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 *********************************************************/
1810struct TestCase
1811{
1812 const char *name;
1813 int (*func)(void);
1814};
1815
1816static 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
1879int 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