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