[Python-checkins] bpo-36763: Fix _PyRuntime.preconfig.coerce_c_locale (GH-13444)

Victor Stinner webhook-mailer at python.org
Mon May 20 11:16:55 EDT 2019


https://github.com/python/cpython/commit/0f72147ce2b3d65235b41eddc6a57be40237b5c7
commit: 0f72147ce2b3d65235b41eddc6a57be40237b5c7
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2019-05-20T17:16:38+02:00
summary:

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.

files:
M Include/cpython/pylifecycle.h
M Python/preconfig.c
M Python/pylifecycle.c

diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h
index 1e1dabe59ff5..ba5666465d7e 100644
--- a/Include/cpython/pylifecycle.h
+++ b/Include/cpython/pylifecycle.h
@@ -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);
 
 /* Legacy locale support */
-PyAPI_FUNC(void) _Py_CoerceLegacyLocale(int warn);
-PyAPI_FUNC(int) _Py_LegacyLocaleDetected(void);
+PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn);
+PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn);
 PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category);
 
 #ifdef __cplusplus
diff --git a/Python/preconfig.c b/Python/preconfig.c
index 71a6ee6c072e..4df6208cadb8 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -660,7 +660,7 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config)
        It is only coerced if if the LC_CTYPE locale is "C". */
     if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
         /* The C locale enables the C locale coercion (PEP 538) */
-        if (_Py_LegacyLocaleDetected()) {
+        if (_Py_LegacyLocaleDetected(0)) {
             config->coerce_c_locale = 2;
         }
         else {
@@ -888,32 +888,38 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
    - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
      (PEP 540)
 
-   If the memory allocator is changed, config is re-allocated with new
-   allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
+   The applied configuration is written into _PyRuntime.preconfig.
+   If the C locale cannot be coerced, set coerce_c_locale to 0.
 
    Do nothing if called after Py_Initialize(): ignore the new
    pre-configuration. */
 _PyInitError
-_PyPreConfig_Write(const _PyPreConfig *config)
+_PyPreConfig_Write(const _PyPreConfig *src_config)
 {
+    _PyPreConfig config;
+    _PyPreConfig_InitFromPreConfig(&config, src_config);
+
     if (_PyRuntime.core_initialized) {
         /* bpo-34008: Calling this functions after Py_Initialize() ignores
            the new configuration. */
         return _Py_INIT_OK();
     }
 
-    PyMemAllocatorName name = (PyMemAllocatorName)config->allocator;
+    PyMemAllocatorName name = (PyMemAllocatorName)config.allocator;
     if (name != PYMEM_ALLOCATOR_NOT_SET) {
         if (_PyMem_SetupAllocators(name) < 0) {
             return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
         }
     }
 
-    _PyPreConfig_SetGlobalConfig(config);
+    _PyPreConfig_SetGlobalConfig(&config);
 
-    if (config->configure_locale) {
-        if (config->coerce_c_locale) {
-            _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
+    if (config.configure_locale) {
+        if (config.coerce_c_locale) {
+            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 */
@@ -921,7 +927,7 @@ _PyPreConfig_Write(const _PyPreConfig *config)
     }
 
     /* Write the new pre-configuration into _PyRuntime */
-    _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
+    _PyPreConfig_Copy(&_PyRuntime.preconfig, &config);
 
     return _Py_INIT_OK();
 }
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 01f725f8f45a..01344db410a0 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -231,9 +231,18 @@ init_importlib_external(PyInterpreterState *interp)
  */
 
 int
-_Py_LegacyLocaleDetected(void)
+_Py_LegacyLocaleDetected(int warn)
 {
 #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 */
     /* 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
@@ -257,7 +266,7 @@ static void
 emit_stderr_warning_for_legacy_locale(_PyRuntimeState *runtime)
 {
     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);
     }
 }
@@ -292,7 +301,7 @@ static const char C_LOCALE_COERCION_WARNING[] =
     "Python detected LC_CTYPE=C: LC_CTYPE coerced to %.20s (set another locale "
     "or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior).\n";
 
-static void
+static int
 _coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
 {
     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)) {
         fprintf(stderr,
                 "Error setting LC_CTYPE, skipping C locale coercion\n");
-        return;
+        return 0;
     }
     if (warn) {
         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 */
     _Py_SetLocaleFromEnv(LC_ALL);
+    return 1;
 }
 #endif
 
-void
+int
 _Py_CoerceLegacyLocale(int warn)
 {
+    int coerced = 0;
 #ifdef PY_COERCE_C_LOCALE
     char *oldloc = NULL;
 
     oldloc = _PyMem_RawStrdup(setlocale(LC_CTYPE, NULL));
     if (oldloc == NULL) {
-        return;
+        return coerced;
     }
 
     const char *locale_override = getenv("LC_ALL");
@@ -345,7 +356,7 @@ _Py_CoerceLegacyLocale(int warn)
                 }
 #endif
                 /* Successfully configured locale, so make it the default */
-                _coerce_default_locale_settings(warn, target);
+                coerced = _coerce_default_locale_settings(warn, target);
                 goto done;
             }
         }
@@ -357,6 +368,7 @@ _Py_CoerceLegacyLocale(int warn)
 done:
     PyMem_RawFree(oldloc);
 #endif
+    return coerced;
 }
 
 /* _Py_SetLocaleFromEnv() is a wrapper around setlocale(category, "") to



More information about the Python-checkins mailing list