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