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