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