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