• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <Python.h>
2 #include "internal/import.h"
3 #include "pythread.h"
4 #include <inttypes.h>
5 #include <stdio.h>
6 #include <wchar.h>
7 
8 /*********************************************************
9  * Embedded interpreter tests that need a custom exe
10  *
11  * Executed via 'EmbeddingTests' in Lib/test/test_capi.py
12  *********************************************************/
13 
_testembed_Py_Initialize(void)14 static void _testembed_Py_Initialize(void)
15 {
16     /* HACK: the "./" at front avoids a search along the PATH in
17        Modules/getpath.c */
18     Py_SetProgramName(L"./_testembed");
19     Py_Initialize();
20 }
21 
22 
23 /*****************************************************
24  * Test repeated initialisation and subinterpreters
25  *****************************************************/
26 
print_subinterp(void)27 static void print_subinterp(void)
28 {
29     /* Output information about the interpreter in the format
30        expected in Lib/test/test_capi.py (test_subinterps). */
31     PyThreadState *ts = PyThreadState_Get();
32     PyInterpreterState *interp = ts->interp;
33     int64_t id = PyInterpreterState_GetID(interp);
34     printf("interp %" PRId64 " <0x%" PRIXPTR ">, thread state <0x%" PRIXPTR ">: ",
35             id, (uintptr_t)interp, (uintptr_t)ts);
36     fflush(stdout);
37     PyRun_SimpleString(
38         "import sys;"
39         "print('id(modules) =', id(sys.modules));"
40         "sys.stdout.flush()"
41     );
42 }
43 
test_repeated_init_and_subinterpreters(void)44 static int test_repeated_init_and_subinterpreters(void)
45 {
46     PyThreadState *mainstate, *substate;
47     PyGILState_STATE gilstate;
48     int i, j;
49 
50     for (i=0; i<15; i++) {
51         printf("--- Pass %d ---\n", i);
52         _testembed_Py_Initialize();
53         mainstate = PyThreadState_Get();
54 
55         PyEval_InitThreads();
56         PyEval_ReleaseThread(mainstate);
57 
58         gilstate = PyGILState_Ensure();
59         print_subinterp();
60         PyThreadState_Swap(NULL);
61 
62         for (j=0; j<3; j++) {
63             substate = Py_NewInterpreter();
64             print_subinterp();
65             Py_EndInterpreter(substate);
66         }
67 
68         PyThreadState_Swap(mainstate);
69         print_subinterp();
70         PyGILState_Release(gilstate);
71 
72         PyEval_RestoreThread(mainstate);
73         Py_Finalize();
74     }
75     return 0;
76 }
77 
78 /*****************************************************
79  * Test forcing a particular IO encoding
80  *****************************************************/
81 
check_stdio_details(const char * encoding,const char * errors)82 static void check_stdio_details(const char *encoding, const char * errors)
83 {
84     /* Output info for the test case to check */
85     if (encoding) {
86         printf("Expected encoding: %s\n", encoding);
87     } else {
88         printf("Expected encoding: default\n");
89     }
90     if (errors) {
91         printf("Expected errors: %s\n", errors);
92     } else {
93         printf("Expected errors: default\n");
94     }
95     fflush(stdout);
96     /* Force the given IO encoding */
97     Py_SetStandardStreamEncoding(encoding, errors);
98     _testembed_Py_Initialize();
99     PyRun_SimpleString(
100         "import sys;"
101         "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));"
102         "print('stdout: {0.encoding}:{0.errors}'.format(sys.stdout));"
103         "print('stderr: {0.encoding}:{0.errors}'.format(sys.stderr));"
104         "sys.stdout.flush()"
105     );
106     Py_Finalize();
107 }
108 
test_forced_io_encoding(void)109 static int test_forced_io_encoding(void)
110 {
111     /* Check various combinations */
112     printf("--- Use defaults ---\n");
113     check_stdio_details(NULL, NULL);
114     printf("--- Set errors only ---\n");
115     check_stdio_details(NULL, "ignore");
116     printf("--- Set encoding only ---\n");
117     check_stdio_details("latin-1", NULL);
118     printf("--- Set encoding and errors ---\n");
119     check_stdio_details("latin-1", "replace");
120 
121     /* Check calling after initialization fails */
122     Py_Initialize();
123 
124     if (Py_SetStandardStreamEncoding(NULL, NULL) == 0) {
125         printf("Unexpected success calling Py_SetStandardStreamEncoding");
126     }
127     Py_Finalize();
128     return 0;
129 }
130 
131 /*********************************************************
132  * Test parts of the C-API that work before initialization
133  *********************************************************/
134 
135 /* The pre-initialization tests tend to break by segfaulting, so explicitly
136  * flushed progress messages make the broken API easier to find when they fail.
137  */
138 #define _Py_EMBED_PREINIT_CHECK(msg) \
139     do {printf(msg); fflush(stdout);} while (0);
140 
test_pre_initialization_api(void)141 static int test_pre_initialization_api(void)
142 {
143     /* Leading "./" ensures getpath.c can still find the standard library */
144     _Py_EMBED_PREINIT_CHECK("Checking Py_DecodeLocale\n");
145     wchar_t *program = Py_DecodeLocale("./spam", NULL);
146     if (program == NULL) {
147         fprintf(stderr, "Fatal error: cannot decode program name\n");
148         return 1;
149     }
150     _Py_EMBED_PREINIT_CHECK("Checking Py_SetProgramName\n");
151     Py_SetProgramName(program);
152 
153     _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
154     Py_Initialize();
155     _Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
156     PyRun_SimpleString("import sys; "
157                        "print('sys.executable:', sys.executable)");
158     _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n");
159     Py_Finalize();
160 
161     _Py_EMBED_PREINIT_CHECK("Freeing memory allocated by Py_DecodeLocale\n");
162     PyMem_RawFree(program);
163     return 0;
164 }
165 
166 
167 /* bpo-33042: Ensure embedding apps can predefine sys module options */
test_pre_initialization_sys_options(void)168 static int test_pre_initialization_sys_options(void)
169 {
170     /* We allocate a couple of the options dynamically, and then delete
171      * them before calling Py_Initialize. This ensures the interpreter isn't
172      * relying on the caller to keep the passed in strings alive.
173      */
174     const wchar_t *static_warnoption = L"once";
175     const wchar_t *static_xoption = L"also_not_an_option=2";
176     size_t warnoption_len = wcslen(static_warnoption);
177     size_t xoption_len = wcslen(static_xoption);
178     wchar_t *dynamic_once_warnoption = \
179              (wchar_t *) calloc(warnoption_len+1, sizeof(wchar_t));
180     wchar_t *dynamic_xoption = \
181              (wchar_t *) calloc(xoption_len+1, sizeof(wchar_t));
182     wcsncpy(dynamic_once_warnoption, static_warnoption, warnoption_len+1);
183     wcsncpy(dynamic_xoption, static_xoption, xoption_len+1);
184 
185     _Py_EMBED_PREINIT_CHECK("Checking PySys_AddWarnOption\n");
186     PySys_AddWarnOption(L"default");
187     _Py_EMBED_PREINIT_CHECK("Checking PySys_ResetWarnOptions\n");
188     PySys_ResetWarnOptions();
189     _Py_EMBED_PREINIT_CHECK("Checking PySys_AddWarnOption linked list\n");
190     PySys_AddWarnOption(dynamic_once_warnoption);
191     PySys_AddWarnOption(L"module");
192     PySys_AddWarnOption(L"default");
193     _Py_EMBED_PREINIT_CHECK("Checking PySys_AddXOption\n");
194     PySys_AddXOption(L"not_an_option=1");
195     PySys_AddXOption(dynamic_xoption);
196 
197     /* Delete the dynamic options early */
198     free(dynamic_once_warnoption);
199     dynamic_once_warnoption = NULL;
200     free(dynamic_xoption);
201     dynamic_xoption = NULL;
202 
203     _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
204     _testembed_Py_Initialize();
205     _Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
206     PyRun_SimpleString("import sys; "
207                        "print('sys.warnoptions:', sys.warnoptions); "
208                        "print('sys._xoptions:', sys._xoptions); "
209                        "warnings = sys.modules['warnings']; "
210                        "latest_filters = [f[0] for f in warnings.filters[:3]]; "
211                        "print('warnings.filters[:3]:', latest_filters)");
212     _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n");
213     Py_Finalize();
214 
215     return 0;
216 }
217 
218 
219 /* bpo-20891: Avoid race condition when initialising the GIL */
bpo20891_thread(void * lockp)220 static void bpo20891_thread(void *lockp)
221 {
222     PyThread_type_lock lock = *((PyThread_type_lock*)lockp);
223 
224     PyGILState_STATE state = PyGILState_Ensure();
225     if (!PyGILState_Check()) {
226         fprintf(stderr, "PyGILState_Check failed!");
227         abort();
228     }
229 
230     PyGILState_Release(state);
231 
232     PyThread_release_lock(lock);
233 
234     PyThread_exit_thread();
235 }
236 
test_bpo20891(void)237 static int test_bpo20891(void)
238 {
239     /* bpo-20891: Calling PyGILState_Ensure in a non-Python thread before
240        calling PyEval_InitThreads() must not crash. PyGILState_Ensure() must
241        call PyEval_InitThreads() for us in this case. */
242     PyThread_type_lock lock = PyThread_allocate_lock();
243     if (!lock) {
244         fprintf(stderr, "PyThread_allocate_lock failed!");
245         return 1;
246     }
247 
248     _testembed_Py_Initialize();
249 
250     unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock);
251     if (thrd == PYTHREAD_INVALID_THREAD_ID) {
252         fprintf(stderr, "PyThread_start_new_thread failed!");
253         return 1;
254     }
255     PyThread_acquire_lock(lock, WAIT_LOCK);
256 
257     Py_BEGIN_ALLOW_THREADS
258     /* wait until the thread exit */
259     PyThread_acquire_lock(lock, WAIT_LOCK);
260     Py_END_ALLOW_THREADS
261 
262     PyThread_free_lock(lock);
263 
264     return 0;
265 }
266 
test_initialize_twice(void)267 static int test_initialize_twice(void)
268 {
269     _testembed_Py_Initialize();
270 
271     /* bpo-33932: Calling Py_Initialize() twice should do nothing
272      * (and not crash!). */
273     Py_Initialize();
274 
275     Py_Finalize();
276 
277     return 0;
278 }
279 
test_initialize_pymain(void)280 static int test_initialize_pymain(void)
281 {
282     wchar_t *argv[] = {L"PYTHON", L"-c",
283                        L"import sys; print(f'Py_Main() after Py_Initialize: sys.argv={sys.argv}')",
284                        L"arg2"};
285     _testembed_Py_Initialize();
286 
287     /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */
288     Py_Main(Py_ARRAY_LENGTH(argv), argv);
289 
290     Py_Finalize();
291 
292     return 0;
293 }
294 
295 
296 static int
dump_config_impl(void)297 dump_config_impl(void)
298 {
299     PyObject *config = NULL;
300     PyObject *dict = NULL;
301 
302     config = PyDict_New();
303     if (config == NULL) {
304         goto error;
305     }
306 
307     /* global config */
308     dict = _Py_GetGlobalVariablesAsDict();
309     if (dict == NULL) {
310         goto error;
311     }
312     if (PyDict_SetItemString(config, "global_config", dict) < 0) {
313         goto error;
314     }
315     Py_CLEAR(dict);
316 
317     /* core config */
318     PyInterpreterState *interp = PyThreadState_Get()->interp;
319     const _PyCoreConfig *core_config = &interp->core_config;
320     dict = _PyCoreConfig_AsDict(core_config);
321     if (dict == NULL) {
322         goto error;
323     }
324     if (PyDict_SetItemString(config, "core_config", dict) < 0) {
325         goto error;
326     }
327     Py_CLEAR(dict);
328 
329     /* main config */
330     const _PyMainInterpreterConfig *main_config = &interp->config;
331     dict = _PyMainInterpreterConfig_AsDict(main_config);
332     if (dict == NULL) {
333         goto error;
334     }
335     if (PyDict_SetItemString(config, "main_config", dict) < 0) {
336         goto error;
337     }
338     Py_CLEAR(dict);
339 
340     PyObject *json = PyImport_ImportModule("json");
341     PyObject *res = PyObject_CallMethod(json, "dumps", "O", config);
342     Py_DECREF(json);
343     Py_CLEAR(config);
344     if (res == NULL) {
345         goto error;
346     }
347 
348     PySys_FormatStdout("%S\n", res);
349     Py_DECREF(res);
350 
351     return 0;
352 
353 error:
354     Py_XDECREF(config);
355     Py_XDECREF(dict);
356     return -1;
357 }
358 
359 
360 static void
dump_config(void)361 dump_config(void)
362 {
363     if (dump_config_impl() < 0) {
364         fprintf(stderr, "failed to dump the configuration:\n");
365         PyErr_Print();
366     }
367 }
368 
369 
test_init_default_config(void)370 static int test_init_default_config(void)
371 {
372     _testembed_Py_Initialize();
373     dump_config();
374     Py_Finalize();
375     return 0;
376 }
377 
378 
test_init_global_config(void)379 static int test_init_global_config(void)
380 {
381     /* FIXME: test Py_IgnoreEnvironmentFlag */
382 
383     putenv("PYTHONUTF8=0");
384     Py_UTF8Mode = 1;
385 
386     /* Test initialization from global configuration variables (Py_xxx) */
387     Py_SetProgramName(L"./globalvar");
388 
389     /* Py_IsolatedFlag is not tested */
390     Py_NoSiteFlag = 1;
391     Py_BytesWarningFlag = 1;
392 
393     putenv("PYTHONINSPECT=");
394     Py_InspectFlag = 1;
395 
396     putenv("PYTHONOPTIMIZE=0");
397     Py_InteractiveFlag = 1;
398 
399     putenv("PYTHONDEBUG=0");
400     Py_OptimizeFlag = 2;
401 
402     /* Py_DebugFlag is not tested */
403 
404     putenv("PYTHONDONTWRITEBYTECODE=");
405     Py_DontWriteBytecodeFlag = 1;
406 
407     putenv("PYTHONVERBOSE=0");
408     Py_VerboseFlag = 1;
409 
410     Py_QuietFlag = 1;
411     Py_NoUserSiteDirectory = 1;
412 
413     putenv("PYTHONUNBUFFERED=");
414     Py_UnbufferedStdioFlag = 1;
415 
416     Py_FrozenFlag = 1;
417 
418     /* FIXME: test Py_LegacyWindowsFSEncodingFlag */
419     /* FIXME: test Py_LegacyWindowsStdioFlag */
420 
421     Py_Initialize();
422     dump_config();
423     Py_Finalize();
424     return 0;
425 }
426 
427 
test_init_from_config(void)428 static int test_init_from_config(void)
429 {
430     /* Test _Py_InitializeFromConfig() */
431     _PyCoreConfig config = _PyCoreConfig_INIT;
432     config.install_signal_handlers = 0;
433 
434     /* FIXME: test ignore_environment */
435 
436     putenv("PYTHONHASHSEED=42");
437     config.use_hash_seed = 1;
438     config.hash_seed = 123;
439 
440     putenv("PYTHONMALLOC=malloc");
441     config.allocator = "malloc_debug";
442 
443     /* dev_mode=1 is tested in test_init_dev_mode() */
444 
445     putenv("PYTHONFAULTHANDLER=");
446     config.faulthandler = 1;
447 
448     putenv("PYTHONTRACEMALLOC=0");
449     config.tracemalloc = 2;
450 
451     putenv("PYTHONPROFILEIMPORTTIME=0");
452     config.import_time = 1;
453 
454     config.show_ref_count = 1;
455     config.show_alloc_count = 1;
456     /* FIXME: test dump_refs: bpo-34223 */
457 
458     putenv("PYTHONMALLOCSTATS=0");
459     config.malloc_stats = 1;
460 
461     /* FIXME: test coerce_c_locale and coerce_c_locale_warn */
462 
463     putenv("PYTHONUTF8=0");
464     Py_UTF8Mode = 0;
465     config.utf8_mode = 1;
466 
467     Py_SetProgramName(L"./globalvar");
468     config.program_name = L"./conf_program_name";
469 
470     static wchar_t* argv[2] = {
471         L"-c",
472         L"pass",
473     };
474     config.argc = Py_ARRAY_LENGTH(argv);
475     config.argv = argv;
476 
477     config.program = L"conf_program";
478 
479     static wchar_t* xoptions[3] = {
480         L"core_xoption1=3",
481         L"core_xoption2=",
482         L"core_xoption3",
483     };
484     config.nxoption = Py_ARRAY_LENGTH(xoptions);
485     config.xoptions = xoptions;
486 
487     static wchar_t* warnoptions[2] = {
488         L"default",
489         L"error::ResourceWarning",
490     };
491     config.nwarnoption = Py_ARRAY_LENGTH(warnoptions);
492     config.warnoptions = warnoptions;
493 
494     /* FIXME: test module_search_path_env */
495     /* FIXME: test home */
496     /* FIXME: test path config: module_search_path .. dll_path */
497 
498     _PyInitError err = _Py_InitializeFromConfig(&config);
499     /* Don't call _PyCoreConfig_Clear() since all strings are static */
500     if (_Py_INIT_FAILED(err)) {
501         _Py_FatalInitError(err);
502     }
503     dump_config();
504     Py_Finalize();
505     return 0;
506 }
507 
508 
test_init_env_putenvs(void)509 static void test_init_env_putenvs(void)
510 {
511     putenv("PYTHONHASHSEED=42");
512     putenv("PYTHONMALLOC=malloc_debug");
513     putenv("PYTHONTRACEMALLOC=2");
514     putenv("PYTHONPROFILEIMPORTTIME=1");
515     putenv("PYTHONMALLOCSTATS=1");
516     putenv("PYTHONUTF8=1");
517     putenv("PYTHONVERBOSE=1");
518     putenv("PYTHONINSPECT=1");
519     putenv("PYTHONOPTIMIZE=2");
520     putenv("PYTHONDONTWRITEBYTECODE=1");
521     putenv("PYTHONUNBUFFERED=1");
522     putenv("PYTHONNOUSERSITE=1");
523     putenv("PYTHONFAULTHANDLER=1");
524     putenv("PYTHONDEVMODE=1");
525     /* FIXME: test PYTHONWARNINGS */
526     /* FIXME: test PYTHONEXECUTABLE */
527     /* FIXME: test PYTHONHOME */
528     /* FIXME: test PYTHONDEBUG */
529     /* FIXME: test PYTHONDUMPREFS */
530     /* FIXME: test PYTHONCOERCECLOCALE */
531     /* FIXME: test PYTHONPATH */
532 }
533 
534 
test_init_env(void)535 static int test_init_env(void)
536 {
537     /* Test initialization from environment variables */
538     Py_IgnoreEnvironmentFlag = 0;
539     test_init_env_putenvs();
540     _testembed_Py_Initialize();
541     dump_config();
542     Py_Finalize();
543     return 0;
544 }
545 
546 
test_init_isolated(void)547 static int test_init_isolated(void)
548 {
549     /* Test _PyCoreConfig.isolated=1 */
550     _PyCoreConfig config = _PyCoreConfig_INIT;
551 
552     /* Set coerce_c_locale and utf8_mode to not depend on the locale */
553     config.coerce_c_locale = 0;
554     config.utf8_mode = 0;
555     /* Use path starting with "./" avoids a search along the PATH */
556     config.program_name = L"./_testembed";
557 
558     Py_IsolatedFlag = 1;
559 
560     test_init_env_putenvs();
561     _PyInitError err = _Py_InitializeFromConfig(&config);
562     if (_Py_INIT_FAILED(err)) {
563         _Py_FatalInitError(err);
564     }
565     dump_config();
566     Py_Finalize();
567     return 0;
568 }
569 
570 
test_init_dev_mode(void)571 static int test_init_dev_mode(void)
572 {
573     _PyCoreConfig config = _PyCoreConfig_INIT;
574     putenv("PYTHONFAULTHANDLER=");
575     putenv("PYTHONMALLOC=");
576     config.dev_mode = 1;
577     config.program_name = L"./_testembed";
578     _PyInitError err = _Py_InitializeFromConfig(&config);
579     if (_Py_INIT_FAILED(err)) {
580         _Py_FatalInitError(err);
581     }
582     dump_config();
583     Py_Finalize();
584     return 0;
585 }
586 
587 
588 /* *********************************************************
589  * List of test cases and the function that implements it.
590  *
591  * Names are compared case-sensitively with the first
592  * argument. If no match is found, or no first argument was
593  * provided, the names of all test cases are printed and
594  * the exit code will be -1.
595  *
596  * The int returned from test functions is used as the exit
597  * code, and test_capi treats all non-zero exit codes as a
598  * failed test.
599  *********************************************************/
600 struct TestCase
601 {
602     const char *name;
603     int (*func)(void);
604 };
605 
606 static struct TestCase TestCases[] = {
607     { "forced_io_encoding", test_forced_io_encoding },
608     { "repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters },
609     { "pre_initialization_api", test_pre_initialization_api },
610     { "pre_initialization_sys_options", test_pre_initialization_sys_options },
611     { "bpo20891", test_bpo20891 },
612     { "initialize_twice", test_initialize_twice },
613     { "initialize_pymain", test_initialize_pymain },
614     { "init_default_config", test_init_default_config },
615     { "init_global_config", test_init_global_config },
616     { "init_from_config", test_init_from_config },
617     { "init_env", test_init_env },
618     { "init_dev_mode", test_init_dev_mode },
619     { "init_isolated", test_init_isolated },
620     { NULL, NULL }
621 };
622 
main(int argc,char * argv[])623 int main(int argc, char *argv[])
624 {
625     if (argc > 1) {
626         for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
627             if (strcmp(argv[1], tc->name) == 0)
628                 return (*tc->func)();
629         }
630     }
631 
632     /* No match found, or no test name provided, so display usage */
633     printf("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"
634            "Normally executed via 'EmbeddingTests' in Lib/test/test_embed.py\n\n"
635            "Usage: %s TESTNAME\n\nAll available tests:\n", argv[0]);
636     for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
637         printf("  %s\n", tc->name);
638     }
639 
640     /* Non-zero exit code will cause test_embed.py tests to fail.
641        This is intentional. */
642     return -1;
643 }
644