diff options
| author | Victor Stinner <vstinner@redhat.com> | 2018-08-05 12:31:59 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-05 12:31:59 +0200 |
| commit | 0c90d6f75931da4fec84d06c2efe9dd94bb96b77 (patch) | |
| tree | ec34949a2d8b022b854acb0e885552c8fc0dd5ff /Modules/main.c | |
| parent | e65ec491fbaa14db61a6559eb269733616b0e7f0 (diff) | |
| download | cpython-git-0c90d6f75931da4fec84d06c2efe9dd94bb96b77.tar.gz | |
[3.7] bpo-34247: Fix Python 3.7 initialization (#8659)
* -X dev: it is now possible to override the memory allocator using
PYTHONMALLOC even if the developer mode is enabled.
* Add _Py_InitializeFromConfig()
* Add _Py_Initialize_ReadEnvVars() to set global configuration
variables from environment variables
* Fix the code to initialize Python: Py_Initialize() now also reads
environment variables
* _Py_InitializeCore() can now be called twice: the second call
only replaces the configuration.
* Write unit tests on Py_Initialize() and the different ways to
configure Python
* The isolated mode now always sets Py_IgnoreEnvironmentFlag and
Py_NoUserSiteDirectory to 1.
* pymain_read_conf() now saves/restores the configuration
if the encoding changed
Diffstat (limited to 'Modules/main.c')
| -rw-r--r-- | Modules/main.c | 301 |
1 files changed, 196 insertions, 105 deletions
diff --git a/Modules/main.c b/Modules/main.c index 1f1bf53ed4..6a707c47d5 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -1364,9 +1364,24 @@ pymain_update_sys_path(_PyMain *pymain, PyObject *path0) } +void +_PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config) +{ +#define COPY_FLAG(ATTR, VALUE) \ + if (config->ATTR == -1) { \ + config->ATTR = VALUE; \ + } + + COPY_FLAG(ignore_environment, Py_IgnoreEnvironmentFlag); + COPY_FLAG(utf8_mode, Py_UTF8Mode); + +#undef COPY_FLAG +} + + /* Get Py_xxx global configuration variables */ static void -pymain_get_global_config(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +cmdline_get_global_config(_Py_CommandLineDetails *cmdline) { cmdline->bytes_warning = Py_BytesWarningFlag; cmdline->debug = Py_DebugFlag; @@ -1385,15 +1400,24 @@ pymain_get_global_config(_PyMain *pymain, _Py_CommandLineDetails *cmdline) cmdline->legacy_windows_stdio = Py_LegacyWindowsStdioFlag; #endif cmdline->check_hash_pycs_mode = _Py_CheckHashBasedPycsMode ; +} - pymain->config.ignore_environment = Py_IgnoreEnvironmentFlag; - pymain->config.utf8_mode = Py_UTF8Mode; + +void +_PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config) +{ + Py_IgnoreEnvironmentFlag = config->ignore_environment; + Py_UTF8Mode = config->utf8_mode; + + /* Random or non-zero hash seed */ + Py_HashRandomizationFlag = (config->use_hash_seed == 0 || + config->hash_seed != 0); } /* Set Py_xxx global configuration variables */ static void -pymain_set_global_config(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +cmdline_set_global_config(_Py_CommandLineDetails *cmdline) { Py_BytesWarningFlag = cmdline->bytes_warning; Py_DebugFlag = cmdline->debug; @@ -1412,13 +1436,6 @@ pymain_set_global_config(_PyMain *pymain, _Py_CommandLineDetails *cmdline) Py_LegacyWindowsFSEncodingFlag = cmdline->legacy_windows_fs_encoding; Py_LegacyWindowsStdioFlag = cmdline->legacy_windows_stdio; #endif - - Py_IgnoreEnvironmentFlag = pymain->config.ignore_environment; - Py_UTF8Mode = pymain->config.utf8_mode; - - /* Random or non-zero hash seed */ - Py_HashRandomizationFlag = (pymain->config.use_hash_seed == 0 || - pymain->config.hash_seed != 0); } @@ -1632,7 +1649,7 @@ pymain_wstr_to_int(const wchar_t *wstr, int *result) static _PyInitError -pymain_init_tracemalloc(_PyCoreConfig *config) +config_init_tracemalloc(_PyCoreConfig *config) { int nframe; int valid; @@ -1714,6 +1731,27 @@ cmdline_get_env_flags(_Py_CommandLineDetails *cmdline) } +/* Set global variable variables from environment variables */ +void +_Py_Initialize_ReadEnvVarsNoAlloc(void) +{ + _Py_CommandLineDetails cmdline; + memset(&cmdline, 0, sizeof(cmdline)); + + cmdline_get_global_config(&cmdline); + if (cmdline.isolated) { + Py_IgnoreEnvironmentFlag = 1; + cmdline.no_user_site_directory = 1; + } + if (!Py_IgnoreEnvironmentFlag) { + cmdline_get_env_flags(&cmdline); + } + cmdline_set_global_config(&cmdline); + + /* no need to call pymain_clear_cmdline(), no memory has been allocated */ +} + + static _PyInitError config_init_home(_PyCoreConfig *config) { @@ -1741,17 +1779,15 @@ config_init_home(_PyCoreConfig *config) static _PyInitError config_init_hash_seed(_PyCoreConfig *config) { - if (config->use_hash_seed < 0) { - const char *seed_text = config_get_env_var("PYTHONHASHSEED"); - int use_hash_seed; - unsigned long hash_seed; - if (_Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) { - return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" " - "or an integer in range [0; 4294967295]"); - } - config->use_hash_seed = use_hash_seed; - config->hash_seed = hash_seed; + const char *seed_text = config_get_env_var("PYTHONHASHSEED"); + int use_hash_seed; + unsigned long hash_seed; + if (_Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) { + return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" " + "or an integer in range [0; 4294967295]"); } + config->use_hash_seed = use_hash_seed; + config->hash_seed = hash_seed; return _Py_INIT_OK(); } @@ -1759,12 +1795,6 @@ config_init_hash_seed(_PyCoreConfig *config) static _PyInitError config_init_utf8_mode(_PyCoreConfig *config) { - /* The option was already set by Py_UTF8Mode, - Py_LegacyWindowsFSEncodingFlag or PYTHONLEGACYWINDOWSFSENCODING. */ - if (config->utf8_mode >= 0) { - return _Py_INIT_OK(); - } - const wchar_t *xopt = config_get_xoption(config, L"utf8"); if (xopt) { wchar_t *sep = wcschr(xopt, L'='); @@ -1808,7 +1838,11 @@ config_init_utf8_mode(_PyCoreConfig *config) static _PyInitError config_read_env_vars(_PyCoreConfig *config) { - config->allocator = config_get_env_var("PYTHONMALLOC"); + assert(!config->ignore_environment); + + if (config->allocator == NULL) { + config->allocator = config_get_env_var("PYTHONMALLOC"); + } if (config_get_env_var("PYTHONDUMPREFS")) { config->dump_refs = 1; @@ -1817,16 +1851,18 @@ config_read_env_vars(_PyCoreConfig *config) config->malloc_stats = 1; } - const char *env = config_get_env_var("PYTHONCOERCECLOCALE"); - if (env) { - if (strcmp(env, "0") == 0) { - config->coerce_c_locale = 0; - } - else if (strcmp(env, "warn") == 0) { - config->coerce_c_locale_warn = 1; - } - else { - config->coerce_c_locale = 1; + if (config->coerce_c_locale < 0) { + const char *env = config_get_env_var("PYTHONCOERCECLOCALE"); + if (env) { + if (strcmp(env, "0") == 0) { + config->coerce_c_locale = 0; + } + else if (strcmp(env, "warn") == 0) { + config->coerce_c_locale_warn = 1; + } + else { + config->coerce_c_locale = 1; + } } } @@ -1837,9 +1873,11 @@ config_read_env_vars(_PyCoreConfig *config) } config->module_search_path_env = path; - _PyInitError err = config_init_hash_seed(config); - if (_Py_INIT_FAILED(err)) { - return err; + if (config->use_hash_seed < 0) { + _PyInitError err = config_init_hash_seed(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } return _Py_INIT_OK(); @@ -1850,9 +1888,11 @@ static _PyInitError config_read_complex_options(_PyCoreConfig *config) { /* More complex options configured by env var and -X option */ - if (config_get_env_var("PYTHONFAULTHANDLER") - || config_get_xoption(config, L"faulthandler")) { - config->faulthandler = 1; + if (config->faulthandler < 0) { + if (config_get_env_var("PYTHONFAULTHANDLER") + || config_get_xoption(config, L"faulthandler")) { + config->faulthandler = 1; + } } if (config_get_env_var("PYTHONPROFILEIMPORTTIME") || config_get_xoption(config, L"importtime")) { @@ -1862,13 +1902,13 @@ config_read_complex_options(_PyCoreConfig *config) config_get_env_var("PYTHONDEVMODE")) { config->dev_mode = 1; - config->faulthandler = 1; - config->allocator = "debug"; } - _PyInitError err = pymain_init_tracemalloc(config); - if (_Py_INIT_FAILED(err)) { - return err; + if (config->tracemalloc < 0) { + _PyInitError err = config_init_tracemalloc(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } return _Py_INIT_OK(); } @@ -1892,10 +1932,12 @@ pymain_read_conf_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) /* Set Py_IgnoreEnvironmentFlag for Py_GETENV() */ _PyCoreConfig *config = &pymain->config; - Py_IgnoreEnvironmentFlag = config->ignore_environment; + Py_IgnoreEnvironmentFlag = config->ignore_environment || cmdline->isolated; /* Get environment variables */ - cmdline_get_env_flags(cmdline); + if (!Py_IgnoreEnvironmentFlag) { + cmdline_get_env_flags(cmdline); + } err = cmdline_init_env_warnoptions(cmdline); if (_Py_INIT_FAILED(err)) { @@ -1940,6 +1982,8 @@ pymain_read_conf_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) static int pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) { + _PyCoreConfig *config = &pymain->config; + _PyCoreConfig save_config = _PyCoreConfig_INIT; int res = -1; char *oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); @@ -1953,10 +1997,15 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) int locale_coerced = 0; int loops = 0; - int init_ignore_env = pymain->config.ignore_environment; + int init_ignore_env = config->ignore_environment; + + if (_PyCoreConfig_Copy(&save_config, config) < 0) { + pymain->err = _Py_INIT_NO_MEMORY(); + goto done; + } while (1) { - int utf8_mode = pymain->config.utf8_mode; + int init_utf8_mode = config->utf8_mode; int encoding_changed = 0; /* Watchdog to prevent an infinite loop */ @@ -1987,20 +2036,20 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) * See the documentation of the PYTHONCOERCECLOCALE setting for more * details. */ - if (pymain->config.coerce_c_locale == 1 && !locale_coerced) { + if (config->coerce_c_locale == 1 && !locale_coerced) { locale_coerced = 1; - _Py_CoerceLegacyLocale(&pymain->config); + _Py_CoerceLegacyLocale(config); encoding_changed = 1; } - if (utf8_mode == -1) { - if (pymain->config.utf8_mode == 1) { + if (init_utf8_mode == -1) { + if (config->utf8_mode == 1) { /* UTF-8 Mode enabled */ encoding_changed = 1; } } else { - if (pymain->config.utf8_mode != utf8_mode) { + if (config->utf8_mode != init_utf8_mode) { encoding_changed = 1; } } @@ -2013,12 +2062,18 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) Py_DecodeLocale(). Reset Py_IgnoreEnvironmentFlag, modified by pymain_read_conf_impl(). Reset Py_IsolatedFlag and Py_NoSiteFlag modified by _PyCoreConfig_Read(). */ - Py_UTF8Mode = pymain->config.utf8_mode; + int new_utf8_mode = config->utf8_mode; Py_IgnoreEnvironmentFlag = init_ignore_env; - _PyCoreConfig_Clear(&pymain->config); + if (_PyCoreConfig_Copy(config, &save_config) < 0) { + pymain->err = _Py_INIT_NO_MEMORY(); + goto done; + } pymain_clear_cmdline(pymain, cmdline); memset(cmdline, 0, sizeof(*cmdline)); - pymain_get_global_config(pymain, cmdline); + + cmdline_get_global_config(cmdline); + _PyCoreConfig_GetGlobalConfig(config); + config->utf8_mode = new_utf8_mode; /* The encoding changed: read again the configuration with the new encoding */ @@ -2026,6 +2081,7 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) res = 0; done: + _PyCoreConfig_Clear(&save_config); if (oldloc != NULL) { setlocale(LC_ALL, oldloc); PyMem_RawFree(oldloc); @@ -2038,10 +2094,6 @@ done: static void config_init_locale(_PyCoreConfig *config) { - if (config->utf8_mode >= 0 && config->coerce_c_locale >= 0) { - return; - } - if (_Py_LegacyLocaleDetected()) { /* POSIX locale: enable C locale coercion and UTF-8 Mode */ if (config->utf8_mode < 0) { @@ -2050,15 +2102,6 @@ config_init_locale(_PyCoreConfig *config) if (config->coerce_c_locale < 0) { config->coerce_c_locale = 1; } - return; - } - - /* By default, C locale coercion and UTF-8 Mode are disabled */ - if (config->coerce_c_locale < 0) { - config->coerce_c_locale = 0; - } - if (config->utf8_mode < 0) { - config->utf8_mode = 0; } } @@ -2175,9 +2218,14 @@ _PyCoreConfig_Read(_PyCoreConfig *config) { _PyInitError err; - err = config_read_env_vars(config); - if (_Py_INIT_FAILED(err)) { - return err; + _PyCoreConfig_GetGlobalConfig(config); + + assert(config->ignore_environment >= 0); + if (!config->ignore_environment) { + err = config_read_env_vars(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } /* -X options */ @@ -2193,26 +2241,29 @@ _PyCoreConfig_Read(_PyCoreConfig *config) return err; } - err = config_init_utf8_mode(config); - if (_Py_INIT_FAILED(err)) { - return err; + if (config->utf8_mode < 0) { + err = config_init_utf8_mode(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } - err = config_init_home(config); - if (_Py_INIT_FAILED(err)) { - return err; + if (config->home == NULL) { + err = config_init_home(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } - err = config_init_program_name(config); - if (_Py_INIT_FAILED(err)) { - return err; + if (config->program_name == NULL) { + err = config_init_program_name(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } - config_init_locale(config); - - /* Signal handlers are installed by default */ - if (config->install_signal_handlers < 0) { - config->install_signal_handlers = 1; + if (config->utf8_mode < 0 || config->coerce_c_locale < 0) { + config_init_locale(config); } if (!config->_disable_importlib) { @@ -2221,6 +2272,39 @@ _PyCoreConfig_Read(_PyCoreConfig *config) return err; } } + + /* default values */ + if (config->dev_mode) { + if (config->faulthandler < 0) { + config->faulthandler = 1; + } + if (config->allocator == NULL) { + config->allocator = "debug"; + } + } + if (config->install_signal_handlers < 0) { + config->install_signal_handlers = 1; + } + if (config->use_hash_seed < 0) { + config->use_hash_seed = 0; + config->hash_seed = 0; + } + if (config->faulthandler < 0) { + config->faulthandler = 0; + } + if (config->tracemalloc < 0) { + config->tracemalloc = 0; + } + if (config->coerce_c_locale < 0) { + config->coerce_c_locale = 0; + } + if (config->utf8_mode < 0) { + config->utf8_mode = 0; + } + if (config->argc < 0) { + config->argc = 0; + } + return _Py_INIT_OK(); } @@ -2289,6 +2373,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) config->LEN = config2->LEN; \ } while (0) + COPY_ATTR(install_signal_handlers); COPY_ATTR(ignore_environment); COPY_ATTR(use_hash_seed); COPY_ATTR(hash_seed); @@ -2302,6 +2387,9 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) COPY_ATTR(show_alloc_count); COPY_ATTR(dump_refs); COPY_ATTR(malloc_stats); + + COPY_ATTR(coerce_c_locale); + COPY_ATTR(coerce_c_locale_warn); COPY_ATTR(utf8_mode); COPY_STR_ATTR(module_search_path_env); @@ -2457,14 +2545,14 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, static int -pymain_init_python_main(_PyMain *pymain) +pymain_init_python_main(_PyMain *pymain, PyInterpreterState *interp) { _PyInitError err; _PyMainInterpreterConfig main_config = _PyMainInterpreterConfig_INIT; - err = _PyMainInterpreterConfig_Read(&main_config, &pymain->config); + err = _PyMainInterpreterConfig_Read(&main_config, &interp->core_config); if (!_Py_INIT_FAILED(err)) { - err = _Py_InitializeMainInterpreter(&main_config); + err = _Py_InitializeMainInterpreter(interp, &main_config); } _PyMainInterpreterConfig_Clear(&main_config); @@ -2615,11 +2703,17 @@ pymain_cmdline(_PyMain *pymain) _Py_CommandLineDetails cmdline; memset(&cmdline, 0, sizeof(cmdline)); - pymain_get_global_config(pymain, &cmdline); + cmdline_get_global_config(&cmdline); + _PyCoreConfig_GetGlobalConfig(&pymain->config); int res = pymain_cmdline_impl(pymain, &cmdline); - pymain_set_global_config(pymain, &cmdline); + cmdline_set_global_config(&cmdline); + _PyCoreConfig_SetGlobalConfig(&pymain->config); + if (Py_IsolatedFlag) { + Py_IgnoreEnvironmentFlag = 1; + Py_NoUserSiteDirectory = 1; + } pymain_clear_cmdline(pymain, &cmdline); @@ -2649,16 +2743,13 @@ pymain_main(_PyMain *pymain) pymain_init_stdio(pymain); - /* bpo-34008: For backward compatibility reasons, calling Py_Main() after - Py_Initialize() ignores the new configuration. */ - if (!_PyRuntime.initialized) { - pymain->err = _Py_InitializeCore(&pymain->config); - if (_Py_INIT_FAILED(pymain->err)) { - _Py_FatalInitError(pymain->err); - } + PyInterpreterState *interp; + pymain->err = _Py_InitializeCore(&interp, &pymain->config); + if (_Py_INIT_FAILED(pymain->err)) { + _Py_FatalInitError(pymain->err); } - if (pymain_init_python_main(pymain) < 0) { + if (pymain_init_python_main(pymain, interp) < 0) { _Py_FatalInitError(pymain->err); } |
