#ifndef Py_BUILD_CORE_MODULE
# define Py_BUILD_CORE_MODULE
#endif
/* Always enable assertion (even in release mode) */
#undef NDEBUG
#include
#include "pycore_initconfig.h" // _PyConfig_InitCompatConfig()
#include "pycore_runtime.h" // _PyRuntime
#include "pycore_import.h" // _PyImport_FrozenBootstrap
#include
#include
#include // putenv()
#include
int main_argc;
char **main_argv;
/*********************************************************
* Embedded interpreter tests that need a custom exe
*
* Executed via Lib/test/test_embed.py
*********************************************************/
// Use to display the usage
#define PROGRAM "test_embed"
/* Use path starting with "./" avoids a search along the PATH */
#define PROGRAM_NAME L"./_testembed"
#define INIT_LOOPS 4
// Ignore Py_DEPRECATED() compiler warnings: deprecated functions are
// tested on purpose here.
_Py_COMP_DIAG_PUSH
_Py_COMP_DIAG_IGNORE_DEPR_DECLS
static void error(const char *msg)
{
fprintf(stderr, "ERROR: %s\n", msg);
fflush(stderr);
}
static void config_set_string(PyConfig *config, wchar_t **config_str, const wchar_t *str)
{
PyStatus status = PyConfig_SetString(config, config_str, str);
if (PyStatus_Exception(status)) {
PyConfig_Clear(config);
Py_ExitStatusException(status);
}
}
static void config_set_program_name(PyConfig *config)
{
const wchar_t *program_name = PROGRAM_NAME;
config_set_string(config, &config->program_name, program_name);
}
static void init_from_config_clear(PyConfig *config)
{
PyStatus status = Py_InitializeFromConfig(config);
PyConfig_Clear(config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
}
static void _testembed_Py_InitializeFromConfig(void)
{
PyConfig config;
_PyConfig_InitCompatConfig(&config);
config_set_program_name(&config);
init_from_config_clear(&config);
}
static void _testembed_Py_Initialize(void)
{
Py_SetProgramName(PROGRAM_NAME);
Py_Initialize();
}
/*****************************************************
* Test repeated initialisation and subinterpreters
*****************************************************/
static void print_subinterp(void)
{
/* Output information about the interpreter in the format
expected in Lib/test/test_capi.py (test_subinterps). */
PyThreadState *ts = PyThreadState_Get();
PyInterpreterState *interp = ts->interp;
int64_t id = PyInterpreterState_GetID(interp);
printf("interp %" PRId64 " , thread state : ",
id, (uintptr_t)interp, (uintptr_t)ts);
fflush(stdout);
PyRun_SimpleString(
"import sys;"
"print('id(modules) =', id(sys.modules));"
"sys.stdout.flush()"
);
}
static int test_repeated_init_and_subinterpreters(void)
{
PyThreadState *mainstate, *substate;
PyGILState_STATE gilstate;
for (int i=1; i 3) {
code = main_argv[i+2];
}
_testembed_Py_InitializeFromConfig();
int err = PyRun_SimpleString(code);
Py_Finalize();
if (err) {
return 1;
}
}
return 0;
}
/****************************************************************************
* Test the Py_Initialize(Ex) convenience/compatibility wrappers
***************************************************************************/
// This is here to help ensure there are no wrapper resource leaks (gh-96853)
static int test_repeated_simple_init(void)
{
for (int i=1; i parse_argv = 1;
config_set_argv(config, Py_ARRAY_LENGTH(argv), argv);
config_set_string(config, &config->program_name, L"./python3");
}
static int test_init_run_main(void)
{
PyConfig config;
PyConfig_InitPythonConfig(&config);
configure_init_main(&config);
init_from_config_clear(&config);
return Py_RunMain();
}
static int test_init_main(void)
{
PyConfig config;
PyConfig_InitPythonConfig(&config);
configure_init_main(&config);
config._init_main = 0;
init_from_config_clear(&config);
/* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
int res = PyRun_SimpleString(
"import sys; "
"print('Run Python code before _Py_InitializeMain', "
"file=sys.stderr)");
if (res < 0) {
exit(1);
}
PyStatus status = _Py_InitializeMain();
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
return Py_RunMain();
}
static int test_run_main(void)
{
PyConfig config;
PyConfig_InitPythonConfig(&config);
wchar_t *argv[] = {L"python3", L"-c",
(L"import sys; "
L"print(f'Py_RunMain(): sys.argv={sys.argv}')"),
L"arg2"};
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
config_set_string(&config, &config.program_name, L"./python3");
init_from_config_clear(&config);
return Py_RunMain();
}
static int test_run_main_loop(void)
{
// bpo-40413: Calling Py_InitializeFromConfig()+Py_RunMain() multiple
// times must not crash.
for (int i=0; icalloc(allocator->ctx, nelem, elsize);
}
static void *
realloc_wrapper(void *ctx, void *ptr, size_t new_size)
{
PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
return allocator->realloc(allocator->ctx, ptr, new_size);
}
static void
free_wrapper(void *ctx, void *ptr)
{
PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
allocator->free(allocator->ctx, ptr);
}
static void
wrap_allocator(PyMemAllocatorEx *allocator)
{
PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, allocator);
PyMemAllocatorEx wrapper = {
.malloc = &malloc_wrapper,
.calloc = &calloc_wrapper,
.realloc = &realloc_wrapper,
.free = &free_wrapper,
.ctx = allocator,
};
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &wrapper);
}
static void
unwrap_allocator(PyMemAllocatorEx *allocator)
{
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, allocator);
}
static int
test_get_incomplete_frame(void)
{
_testembed_Py_InitializeFromConfig();
PyMemAllocatorEx allocator;
wrap_allocator(&allocator);
// Force an allocation with an incomplete (generator) frame:
int result = PyRun_SimpleString("(_ for _ in ())");
unwrap_allocator(&allocator);
Py_Finalize();
return result;
}
/* *********************************************************
* List of test cases and the function that implements it.
*
* Names are compared case-sensitively with the first
* argument. If no match is found, or no first argument was
* provided, the names of all test cases are printed and
* the exit code will be -1.
*
* The int returned from test functions is used as the exit
* code, and test_capi treats all non-zero exit codes as a
* failed test.
*********************************************************/
struct TestCase
{
const char *name;
int (*func)(void);
};
static struct TestCase TestCases[] = {
// Python initialization
{"test_repeated_init_exec", test_repeated_init_exec},
{"test_repeated_simple_init", test_repeated_simple_init},
{"test_forced_io_encoding", test_forced_io_encoding},
{"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters},
{"test_repeated_init_and_inittab", test_repeated_init_and_inittab},
{"test_pre_initialization_api", test_pre_initialization_api},
{"test_pre_initialization_sys_options", test_pre_initialization_sys_options},
{"test_bpo20891", test_bpo20891},
{"test_initialize_twice", test_initialize_twice},
{"test_initialize_pymain", test_initialize_pymain},
{"test_init_initialize_config", test_init_initialize_config},
{"test_preinit_compat_config", test_preinit_compat_config},
{"test_init_compat_config", test_init_compat_config},
{"test_init_global_config", test_init_global_config},
{"test_init_from_config", test_init_from_config},
{"test_init_parse_argv", test_init_parse_argv},
{"test_init_dont_parse_argv", test_init_dont_parse_argv},
{"test_init_compat_env", test_init_compat_env},
{"test_init_python_env", test_init_python_env},
{"test_init_env_dev_mode", test_init_env_dev_mode},
{"test_init_env_dev_mode_alloc", test_init_env_dev_mode_alloc},
{"test_init_dont_configure_locale", test_init_dont_configure_locale},
{"test_init_dev_mode", test_init_dev_mode},
{"test_init_isolated_flag", test_init_isolated_flag},
{"test_preinit_isolated_config", test_preinit_isolated_config},
{"test_init_isolated_config", test_init_isolated_config},
{"test_preinit_python_config", test_preinit_python_config},
{"test_init_python_config", test_init_python_config},
{"test_preinit_isolated1", test_preinit_isolated1},
{"test_preinit_isolated2", test_preinit_isolated2},
{"test_preinit_parse_argv", test_preinit_parse_argv},
{"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv},
{"test_init_read_set", test_init_read_set},
{"test_init_run_main", test_init_run_main},
{"test_init_main", test_init_main},
{"test_init_sys_add", test_init_sys_add},
{"test_init_setpath", test_init_setpath},
{"test_init_setpath_config", test_init_setpath_config},
{"test_init_setpythonhome", test_init_setpythonhome},
{"test_init_is_python_build", test_init_is_python_build},
{"test_init_warnoptions", test_init_warnoptions},
{"test_init_set_config", test_init_set_config},
{"test_run_main", test_run_main},
{"test_run_main_loop", test_run_main_loop},
{"test_get_argc_argv", test_get_argc_argv},
{"test_init_use_frozen_modules", test_init_use_frozen_modules},
{"test_init_main_interpreter_settings", test_init_main_interpreter_settings},
// Audit
{"test_open_code_hook", test_open_code_hook},
{"test_audit", test_audit},
{"test_audit_subinterpreter", test_audit_subinterpreter},
{"test_audit_run_command", test_audit_run_command},
{"test_audit_run_file", test_audit_run_file},
{"test_audit_run_interactivehook", test_audit_run_interactivehook},
{"test_audit_run_startup", test_audit_run_startup},
{"test_audit_run_stdin", test_audit_run_stdin},
// Specific C API
{"test_unicode_id_init", test_unicode_id_init},
#ifndef MS_WINDOWS
{"test_frozenmain", test_frozenmain},
#endif
{"test_get_incomplete_frame", test_get_incomplete_frame},
{NULL, NULL}
};
int main(int argc, char *argv[])
{
main_argc = argc;
main_argv = argv;
if (argc > 1) {
for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
if (strcmp(argv[1], tc->name) == 0)
return (*tc->func)();
}
}
/* No match found, or no test name provided, so display usage */
printf("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"
"Normally executed via 'EmbeddingTests' in Lib/test/test_embed.py\n\n"
"Usage: %s TESTNAME\n\nAll available tests:\n", argv[0]);
for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
printf(" %s\n", tc->name);
}
/* Non-zero exit code will cause test_embed.py tests to fail.
This is intentional. */
return -1;
}