From 67310023f299b5a2fad71fca449b46d280036690 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 1 Jul 2019 19:52:45 +0200 Subject: [PATCH] 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(). --- Lib/test/test_embed.py | 15 +- Modules/main.c | 12 +- Programs/_freeze_importlib.c | 2 +- Programs/_testembed.c | 308 +++++++++++++++-------------------- 4 files changed, 151 insertions(+), 186 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index e1cf4be5066..b2cd55016e4 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -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, diff --git a/Modules/main.c b/Modules/main.c index 853afedd7b9..b126f4554d4 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -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; } diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c index 13375b0a381..74735f279c5 100644 --- a/Programs/_freeze_importlib.c +++ b/Programs/_freeze_importlib.c @@ -88,7 +88,7 @@ main(int argc, char *argv[]) config.site_import = 0; status = PyConfig_SetString(&config, &config.program_name, - L"./_freeze_importlib"); + L"./_freeze_importlib"); if (PyStatus_Exception(status)) { PyConfig_Clear(&config); Py_ExitStatusException(status); diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 9633f4610b5..856144b85e1 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -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[] = { - 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; + wchar_t* argv[] = { + L"python3", L"-c", + (L"import _testinternalcapi, json; " + L"print(json.dumps(_testinternalcapi.get_configs()))"), + L"arg2"}; + 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); }