bpo-36763: Use PyConfig_Clear() (GH-14445)

Stop using "static PyConfig", PyConfig must now always use
dynamically allocated strings: use PyConfig_SetString(),
PyConfig_SetArgv() and PyConfig_Clear().
This commit is contained in:
Victor Stinner 2019-07-01 19:52:45 +02:00 committed by GitHub
parent e6b64b756f
commit 67310023f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 186 deletions

View File

@ -695,10 +695,19 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'pycache_prefix': 'conf_pycache_prefix',
'program_name': './conf_program_name',
'argv': ['-c', 'arg2'],
'argv': ['-c', 'arg2', ],
'parse_argv': 1,
'xoptions': ['xoption1=3', 'xoption2=', 'xoption3'],
'warnoptions': ['error::ResourceWarning', 'default::BytesWarning'],
'xoptions': [
'config_xoption1=3',
'config_xoption2=',
'config_xoption3',
'cmdline_xoption',
],
'warnoptions': [
'config_warnoption',
'cmdline_warnoption',
'default::BytesWarning',
],
'run_command': 'pass\n',
'site_import': 0,

View File

@ -62,7 +62,7 @@ pymain_init(const _PyArgv *args)
PyConfig config;
status = PyConfig_InitPythonConfig(&config);
if (_PyStatus_EXCEPTION(status)) {
return status;
goto done;
}
/* pass NULL as the config: config is read from command line arguments,
@ -74,14 +74,18 @@ pymain_init(const _PyArgv *args)
status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv);
}
if (_PyStatus_EXCEPTION(status)) {
return status;
goto done;
}
status = Py_InitializeFromConfig(&config);
if (_PyStatus_EXCEPTION(status)) {
return status;
goto done;
}
return _PyStatus_OK();
status = _PyStatus_OK();
done:
PyConfig_Clear(&config);
return status;
}

View File

@ -329,6 +329,56 @@ static int test_init_initialize_config(void)
}
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_argv(PyConfig *config, Py_ssize_t argc, wchar_t * const *argv)
{
PyStatus status = PyConfig_SetArgv(config, argc, argv);
if (PyStatus_Exception(status)) {
PyConfig_Clear(config);
Py_ExitStatusException(status);
}
}
static void
config_set_wide_string_list(PyConfig *config, PyWideStringList *list,
Py_ssize_t length, wchar_t **items)
{
PyStatus status = PyConfig_SetWideStringList(config, list, length, items);
if (PyStatus_Exception(status)) {
PyConfig_Clear(config);
Py_ExitStatusException(status);
}
}
static void config_set_program_name(PyConfig *config)
{
/* Use path starting with "./" avoids a search along the PATH */
const wchar_t *program_name = L"./_testembed";
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 int check_init_compat_config(int preinit)
{
PyStatus status;
@ -345,12 +395,8 @@ static int check_init_compat_config(int preinit)
PyConfig config;
_PyConfig_InitCompatConfig(&config);
config.program_name = L"./_testembed";
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config_set_program_name(&config);
init_from_config_clear(&config);
dump_config();
Py_Finalize();
@ -438,7 +484,6 @@ static int test_init_from_config(void)
Py_ExitStatusException(status);
}
/* Test Py_InitializeFromConfig() */
PyConfig config;
_PyConfig_InitCompatConfig(&config);
config.install_signal_handlers = 0;
@ -468,34 +513,37 @@ static int test_init_from_config(void)
config.malloc_stats = 1;
putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
config.pycache_prefix = L"conf_pycache_prefix";
config_set_string(&config, &config.pycache_prefix, L"conf_pycache_prefix");
Py_SetProgramName(L"./globalvar");
config.program_name = L"./conf_program_name";
config_set_string(&config, &config.program_name, L"./conf_program_name");
static wchar_t* argv[] = {
wchar_t* argv[] = {
L"python3",
L"-W",
L"cmdline_warnoption",
L"-X",
L"cmdline_xoption",
L"-c",
L"pass",
L"arg2",
};
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
config.parse_argv = 1;
static wchar_t* xoptions[3] = {
L"xoption1=3",
L"xoption2=",
L"xoption3",
wchar_t* xoptions[3] = {
L"config_xoption1=3",
L"config_xoption2=",
L"config_xoption3",
};
config.xoptions.length = Py_ARRAY_LENGTH(xoptions);
config.xoptions.items = xoptions;
config_set_wide_string_list(&config, &config.xoptions,
Py_ARRAY_LENGTH(xoptions), xoptions);
static wchar_t* warnoptions[1] = {
L"error::ResourceWarning",
wchar_t* warnoptions[1] = {
L"config_warnoption",
};
config.warnoptions.length = Py_ARRAY_LENGTH(warnoptions);
config.warnoptions.items = warnoptions;
config_set_wide_string_list(&config, &config.warnoptions,
Py_ARRAY_LENGTH(warnoptions), warnoptions);
/* FIXME: test pythonpath_env */
/* FIXME: test home */
@ -544,22 +592,20 @@ static int test_init_from_config(void)
Force it to 0 through the config. */
config.legacy_windows_stdio = 0;
#endif
config.stdio_encoding = L"iso8859-1";
config.stdio_errors = L"replace";
config_set_string(&config, &config.stdio_encoding, L"iso8859-1");
config_set_string(&config, &config.stdio_errors, L"replace");
putenv("PYTHONNOUSERSITE=");
Py_NoUserSiteDirectory = 0;
config.user_site_directory = 0;
config.check_hash_pycs_mode = L"always";
config_set_string(&config, &config.check_hash_pycs_mode, L"always");
Py_FrozenFlag = 0;
config.pathconfig_warnings = 0;
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
@ -576,7 +622,9 @@ static int check_init_parse_argv(int parse_argv)
Py_ExitStatusException(status);
}
static wchar_t* argv[] = {
config.parse_argv = parse_argv;
wchar_t* argv[] = {
L"./argv0",
L"-E",
L"-c",
@ -585,15 +633,9 @@ static int check_init_parse_argv(int parse_argv)
L"-v",
L"arg3",
};
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
init_from_config_clear(&config);
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
config.parse_argv = parse_argv;
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
dump_config();
Py_Finalize();
return 0;
@ -664,12 +706,10 @@ static int test_init_python_env(void)
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config.program_name = L"./_testembed";
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config_set_program_name(&config);
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
@ -723,14 +763,10 @@ static int test_init_isolated_flag(void)
Py_IsolatedFlag = 0;
config.isolated = 1;
/* Use path starting with "./" avoids a search along the PATH */
config.program_name = L"./_testembed";
config_set_program_name(&config);
set_all_env_vars();
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
@ -753,13 +789,10 @@ static int test_preinit_isolated1(void)
PyConfig config;
_PyConfig_InitCompatConfig(&config);
config.program_name = L"./_testembed";
config_set_program_name(&config);
set_all_env_vars();
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
@ -787,14 +820,10 @@ static int test_preinit_isolated2(void)
Py_IsolatedFlag = 0;
config.isolated = 1;
/* Use path starting with "./" avoids a search along the PATH */
config.program_name = L"./_testembed";
config_set_program_name(&config);
set_all_env_vars();
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
@ -819,44 +848,28 @@ static int test_preinit_dont_parse_argv(void)
L"script.py"};
status = Py_PreInitializeFromArgs(&preconfig, Py_ARRAY_LENGTH(argv), argv);
if (PyStatus_Exception(status)) {
goto failed;
Py_ExitStatusException(status);
}
PyConfig config;
status = PyConfig_InitIsolatedConfig(&config);
if (PyStatus_Exception(status)) {
goto failed;
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
config.isolated = 0;
/* Pre-initialize implicitly using argv: make sure that -X dev
is used to configure the allocation in preinitialization */
status = PyConfig_SetArgv(&config, Py_ARRAY_LENGTH(argv), argv);
if (PyStatus_Exception(status)) {
goto failed;
}
status = PyConfig_SetString(&config, &config.program_name,
L"./_testembed");
if (PyStatus_Exception(status)) {
goto failed;
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
goto failed;
}
PyConfig_Clear(&config);
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
config_set_program_name(&config);
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
failed:
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
@ -867,36 +880,20 @@ static int test_preinit_parse_argv(void)
status = PyConfig_InitPythonConfig(&config);
if (PyStatus_Exception(status)) {
goto failed;
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
/* Pre-initialize implicitly using argv: make sure that -X dev
is used to configure the allocation in preinitialization */
wchar_t *argv[] = {L"python3", L"-X", L"dev", L"script.py"};
status = PyConfig_SetArgv(&config, Py_ARRAY_LENGTH(argv), argv);
if (PyStatus_Exception(status)) {
goto failed;
}
status = PyConfig_SetString(&config, &config.program_name,
L"./_testembed");
if (PyStatus_Exception(status)) {
goto failed;
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
goto failed;
}
PyConfig_Clear(&config);
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
config_set_program_name(&config);
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
failed:
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
@ -955,13 +952,8 @@ static int check_preinit_isolated_config(int preinit)
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
config.program_name = L"./_testembed";
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
config_set_program_name(&config);
init_from_config_clear(&config);
rt_preconfig = &_PyRuntime.preconfig;
assert(rt_preconfig->isolated == 1);
@ -1017,12 +1009,9 @@ static int check_init_python_config(int preinit)
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config.program_name = L"./_testembed";
config_set_program_name(&config);
init_from_config_clear(&config);
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
dump_config();
Py_Finalize();
return 0;
@ -1061,11 +1050,8 @@ static int test_init_dont_configure_locale(void)
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config.program_name = L"./_testembed";
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config_set_program_name(&config);
init_from_config_clear(&config);
dump_config();
Py_Finalize();
@ -1084,11 +1070,9 @@ static int test_init_dev_mode(void)
putenv("PYTHONFAULTHANDLER=");
putenv("PYTHONMALLOC=");
config.dev_mode = 1;
config.program_name = L"./_testembed";
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
config_set_program_name(&config);
init_from_config_clear(&config);
dump_config();
Py_Finalize();
return 0;
@ -1278,16 +1262,9 @@ static int test_init_read_set(void)
}
/* override executable computed by PyConfig_Read() */
status = PyConfig_SetString(&config, &config.executable, L"my_executable");
if (PyStatus_Exception(status)) {
goto fail;
}
config_set_string(&config, &config.executable, L"my_executable");
init_from_config_clear(&config);
status = Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
if (PyStatus_Exception(status)) {
goto fail;
}
dump_config();
Py_Finalize();
return 0;
@ -1297,19 +1274,18 @@ fail:
}
wchar_t *init_main_argv[] = {
static void configure_init_main(PyConfig *config)
{
wchar_t* argv[] = {
L"python3", L"-c",
(L"import _testinternalcapi, json; "
L"print(json.dumps(_testinternalcapi.get_configs()))"),
L"arg2"};
static void configure_init_main(PyConfig *config)
{
config->argv.length = Py_ARRAY_LENGTH(init_main_argv);
config->argv.items = init_main_argv;
config->parse_argv = 1;
config->program_name = L"./python3";
config_set_argv(config, Py_ARRAY_LENGTH(argv), argv);
config_set_string(config, &config->program_name, L"./python3");
}
@ -1322,11 +1298,7 @@ static int test_init_run_main(void)
Py_ExitStatusException(status);
}
configure_init_main(&config);
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
init_from_config_clear(&config);
return Py_RunMain();
}
@ -1343,11 +1315,7 @@ static int test_init_main(void)
}
configure_init_main(&config);
config._init_main = 0;
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
}
init_from_config_clear(&config);
/* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
int res = PyRun_SimpleString(
@ -1374,35 +1342,19 @@ static int test_run_main(void)
status = PyConfig_InitPythonConfig(&config);
if (PyStatus_Exception(status)) {
goto failed;
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}
wchar_t *argv[] = {L"python3", L"-c",
(L"import sys; "
L"print(f'Py_RunMain(): sys.argv={sys.argv}')"),
L"arg2"};
status = PyConfig_SetArgv(&config, Py_ARRAY_LENGTH(argv), argv);
if (PyStatus_Exception(status)) {
goto failed;
}
status = PyConfig_SetString(&config, &config.program_name,
L"./python3");
if (PyStatus_Exception(status)) {
goto failed;
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
goto failed;
}
PyConfig_Clear(&config);
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();
failed:
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}