bpo-36763: Fix _PyRuntime.preconfig.coerce_c_locale (GH-13444)
_PyRuntime.preconfig.coerce_c_locale can now be used to check if the C locale has been coerced. * Fix _Py_LegacyLocaleDetected(): don't attempt to coerce the C locale if LC_ALL environment variable is set. Add 'warn' parameter: emit_stderr_warning_for_legacy_locale() must not the LC_ALL env var. * _PyPreConfig_Write() sets coerce_c_locale to 0 if _Py_CoerceLegacyLocale() fails.
This commit is contained in:
parent
522ccef869
commit
0f72147ce2
|
@ -69,8 +69,8 @@ PyAPI_FUNC(int) _PyOS_URandom(void *buffer, Py_ssize_t size);
|
||||||
PyAPI_FUNC(int) _PyOS_URandomNonblock(void *buffer, Py_ssize_t size);
|
PyAPI_FUNC(int) _PyOS_URandomNonblock(void *buffer, Py_ssize_t size);
|
||||||
|
|
||||||
/* Legacy locale support */
|
/* Legacy locale support */
|
||||||
PyAPI_FUNC(void) _Py_CoerceLegacyLocale(int warn);
|
PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn);
|
||||||
PyAPI_FUNC(int) _Py_LegacyLocaleDetected(void);
|
PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn);
|
||||||
PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category);
|
PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -660,7 +660,7 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config)
|
||||||
It is only coerced if if the LC_CTYPE locale is "C". */
|
It is only coerced if if the LC_CTYPE locale is "C". */
|
||||||
if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
|
if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
|
||||||
/* The C locale enables the C locale coercion (PEP 538) */
|
/* The C locale enables the C locale coercion (PEP 538) */
|
||||||
if (_Py_LegacyLocaleDetected()) {
|
if (_Py_LegacyLocaleDetected(0)) {
|
||||||
config->coerce_c_locale = 2;
|
config->coerce_c_locale = 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -888,32 +888,38 @@ done:
|
||||||
- set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
|
- set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
|
||||||
(PEP 540)
|
(PEP 540)
|
||||||
|
|
||||||
If the memory allocator is changed, config is re-allocated with new
|
The applied configuration is written into _PyRuntime.preconfig.
|
||||||
allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
|
If the C locale cannot be coerced, set coerce_c_locale to 0.
|
||||||
|
|
||||||
Do nothing if called after Py_Initialize(): ignore the new
|
Do nothing if called after Py_Initialize(): ignore the new
|
||||||
pre-configuration. */
|
pre-configuration. */
|
||||||
_PyInitError
|
_PyInitError
|
||||||
_PyPreConfig_Write(const _PyPreConfig *config)
|
_PyPreConfig_Write(const _PyPreConfig *src_config)
|
||||||
{
|
{
|
||||||
|
_PyPreConfig config;
|
||||||
|
_PyPreConfig_InitFromPreConfig(&config, src_config);
|
||||||
|
|
||||||
if (_PyRuntime.core_initialized) {
|
if (_PyRuntime.core_initialized) {
|
||||||
/* bpo-34008: Calling this functions after Py_Initialize() ignores
|
/* bpo-34008: Calling this functions after Py_Initialize() ignores
|
||||||
the new configuration. */
|
the new configuration. */
|
||||||
return _Py_INIT_OK();
|
return _Py_INIT_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyMemAllocatorName name = (PyMemAllocatorName)config->allocator;
|
PyMemAllocatorName name = (PyMemAllocatorName)config.allocator;
|
||||||
if (name != PYMEM_ALLOCATOR_NOT_SET) {
|
if (name != PYMEM_ALLOCATOR_NOT_SET) {
|
||||||
if (_PyMem_SetupAllocators(name) < 0) {
|
if (_PyMem_SetupAllocators(name) < 0) {
|
||||||
return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
|
return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_PyPreConfig_SetGlobalConfig(config);
|
_PyPreConfig_SetGlobalConfig(&config);
|
||||||
|
|
||||||
if (config->configure_locale) {
|
if (config.configure_locale) {
|
||||||
if (config->coerce_c_locale) {
|
if (config.coerce_c_locale) {
|
||||||
_Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
|
if (!_Py_CoerceLegacyLocale(config.coerce_c_locale_warn)) {
|
||||||
|
/* C locale not coerced */
|
||||||
|
config.coerce_c_locale = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set LC_CTYPE to the user preferred locale */
|
/* Set LC_CTYPE to the user preferred locale */
|
||||||
|
@ -921,7 +927,7 @@ _PyPreConfig_Write(const _PyPreConfig *config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the new pre-configuration into _PyRuntime */
|
/* Write the new pre-configuration into _PyRuntime */
|
||||||
_PyPreConfig_Copy(&_PyRuntime.preconfig, config);
|
_PyPreConfig_Copy(&_PyRuntime.preconfig, &config);
|
||||||
|
|
||||||
return _Py_INIT_OK();
|
return _Py_INIT_OK();
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,9 +231,18 @@ init_importlib_external(PyInterpreterState *interp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
_Py_LegacyLocaleDetected(void)
|
_Py_LegacyLocaleDetected(int warn)
|
||||||
{
|
{
|
||||||
#ifndef MS_WINDOWS
|
#ifndef MS_WINDOWS
|
||||||
|
if (!warn) {
|
||||||
|
const char *locale_override = getenv("LC_ALL");
|
||||||
|
if (locale_override != NULL && *locale_override != '\0') {
|
||||||
|
/* Don't coerce C locale if the LC_ALL environment variable
|
||||||
|
is set */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* On non-Windows systems, the C locale is considered a legacy locale */
|
/* On non-Windows systems, the C locale is considered a legacy locale */
|
||||||
/* XXX (ncoghlan): some platforms (notably Mac OS X) don't appear to treat
|
/* XXX (ncoghlan): some platforms (notably Mac OS X) don't appear to treat
|
||||||
* the POSIX locale as a simple alias for the C locale, so
|
* the POSIX locale as a simple alias for the C locale, so
|
||||||
|
@ -257,7 +266,7 @@ static void
|
||||||
emit_stderr_warning_for_legacy_locale(_PyRuntimeState *runtime)
|
emit_stderr_warning_for_legacy_locale(_PyRuntimeState *runtime)
|
||||||
{
|
{
|
||||||
const _PyPreConfig *preconfig = &runtime->preconfig;
|
const _PyPreConfig *preconfig = &runtime->preconfig;
|
||||||
if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected()) {
|
if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected(1)) {
|
||||||
PySys_FormatStderr("%s", _C_LOCALE_WARNING);
|
PySys_FormatStderr("%s", _C_LOCALE_WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,7 +301,7 @@ static const char C_LOCALE_COERCION_WARNING[] =
|
||||||
"Python detected LC_CTYPE=C: LC_CTYPE coerced to %.20s (set another locale "
|
"Python detected LC_CTYPE=C: LC_CTYPE coerced to %.20s (set another locale "
|
||||||
"or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior).\n";
|
"or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior).\n";
|
||||||
|
|
||||||
static void
|
static int
|
||||||
_coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
|
_coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
|
||||||
{
|
{
|
||||||
const char *newloc = target->locale_name;
|
const char *newloc = target->locale_name;
|
||||||
|
@ -304,7 +313,7 @@ _coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
|
||||||
if (setenv("LC_CTYPE", newloc, 1)) {
|
if (setenv("LC_CTYPE", newloc, 1)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Error setting LC_CTYPE, skipping C locale coercion\n");
|
"Error setting LC_CTYPE, skipping C locale coercion\n");
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
if (warn) {
|
if (warn) {
|
||||||
fprintf(stderr, C_LOCALE_COERCION_WARNING, newloc);
|
fprintf(stderr, C_LOCALE_COERCION_WARNING, newloc);
|
||||||
|
@ -312,18 +321,20 @@ _coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
|
||||||
|
|
||||||
/* Reconfigure with the overridden environment variables */
|
/* Reconfigure with the overridden environment variables */
|
||||||
_Py_SetLocaleFromEnv(LC_ALL);
|
_Py_SetLocaleFromEnv(LC_ALL);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
int
|
||||||
_Py_CoerceLegacyLocale(int warn)
|
_Py_CoerceLegacyLocale(int warn)
|
||||||
{
|
{
|
||||||
|
int coerced = 0;
|
||||||
#ifdef PY_COERCE_C_LOCALE
|
#ifdef PY_COERCE_C_LOCALE
|
||||||
char *oldloc = NULL;
|
char *oldloc = NULL;
|
||||||
|
|
||||||
oldloc = _PyMem_RawStrdup(setlocale(LC_CTYPE, NULL));
|
oldloc = _PyMem_RawStrdup(setlocale(LC_CTYPE, NULL));
|
||||||
if (oldloc == NULL) {
|
if (oldloc == NULL) {
|
||||||
return;
|
return coerced;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *locale_override = getenv("LC_ALL");
|
const char *locale_override = getenv("LC_ALL");
|
||||||
|
@ -345,7 +356,7 @@ _Py_CoerceLegacyLocale(int warn)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Successfully configured locale, so make it the default */
|
/* Successfully configured locale, so make it the default */
|
||||||
_coerce_default_locale_settings(warn, target);
|
coerced = _coerce_default_locale_settings(warn, target);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,6 +368,7 @@ _Py_CoerceLegacyLocale(int warn)
|
||||||
done:
|
done:
|
||||||
PyMem_RawFree(oldloc);
|
PyMem_RawFree(oldloc);
|
||||||
#endif
|
#endif
|
||||||
|
return coerced;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _Py_SetLocaleFromEnv() is a wrapper around setlocale(category, "") to
|
/* _Py_SetLocaleFromEnv() is a wrapper around setlocale(category, "") to
|
||||||
|
|
Loading…
Reference in New Issue