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