8000 bpo-36763: Fix _PyRuntime.preconfig.coerce_c_locale (GH-13444) · python/cpython@0f72147 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0f72147

Browse files
authored
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.
1 parent 522ccef commit 0f72147

File tree

3 files changed

+37
-19
lines changed

3 files changed

+37
-19
lines changed

Include/cpython/pylifecycle.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ PyAPI_FUNC(int) _PyOS_URandom(void *buffer, Py_ssize_t size);
6969
PyAPI_FUNC(int) _PyOS_URandomNonblock(void *buffer, Py_ssize_t size);
7070

7171
/* Legacy locale support */
72-
PyAPI_FUNC(void) _Py_CoerceLegacyLocale(int warn);
73-
PyAPI_FUNC(int) _Py_LegacyLocaleDetected(void);
72+
PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn);
73+
PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn);
7474
PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category);
7575

7676
#ifdef __cplusplus

Python/preconfig.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config)
660660
It is only coerced if if the LC_CTYPE locale is "C". */
661661
if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
662662
/* The C locale enables the C locale coercion (PEP 538) */
663-
if (_Py_LegacyLocaleDetected()) {
663+
if (_Py_LegacyLocaleDetected(0)) {
664664
config->coerce_c_locale = 2;
665665
}
666666
else {
@@ -888,40 +888,46 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
888888
- set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
889889
(PEP 540)
890890
891-
If the memory allocator is changed, config is re-allocated with new
892-
allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
891+
The applied configuration is written into _PyRuntime.preconfig.
892+
If the C locale cannot be coerced, set coerce_c_locale to 0.
893893
894894
Do nothing if called after Py_Initialize(): ignore the new
895895
pre-configuration. */
896896
_PyInitError
897-
_PyPreConfig_Write(const _PyPreConfig *config)
897+
_PyPreConfig_Write(const _PyPreConfig *src_config)
898898
{
899+
_PyPreConfig config;
900+
_PyPreConfig_InitFromPreConfig(&config, src_config);
901+
899902
if (_PyRuntime.core_initialized) {
900903
/* bpo-34008: Calling this functions after Py_Initialize() ignores
901904
the new configuration. */
902905
return _Py_INIT_OK();
903906
}
904907

905-
PyMemAllocatorName name = (PyMemAllocatorName)config->allocator;
908+
PyMemAllocatorName name = (PyMemAllocatorName)config.allocator;
906909
if (name != PYMEM_ALLOCATOR_NOT_SET) {
907910
if (_PyMem_SetupAllocators(name) < 0) {
908911
return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
909912
}
910913
}
911914

912-
_PyPreConfig_SetGlobalConfig(config);
915+
_PyPreConfig_SetGlobalConfig(&config);
913916

914-
if (config->configure_locale) {
915-
if (config->coerce_c_locale) {
916-
_Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
917+
if (config.configure_locale) {
918+
if (config.coerce_c_locale) {
919+
if (!_Py_CoerceLegacyLocale(config.coerce_c_locale_warn)) {
920+
/* C locale not coerced */
921+
config.coerce_c_locale = 0;
922+
}
917923
}
918924

919925
/* Set LC_CTYPE to the user preferred locale */
920926
_Py_SetLocaleFromEnv(LC_CTYPE);
921927
}
922928

923929
/* Write the new pre-configuration into _PyRuntime */
924-
_PyPreConfig_Copy(&_PyRuntime.preconfig, config);
930+
_PyPreConfig_Copy(&_PyRuntime.preconfig, &config);
925931

926932
return _Py_INIT_OK();
927933
}

Python/pylifecycle.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,18 @@ init_importlib_external(PyInterpreterState *interp)
231231
*/
232232

233233
int
234-
_Py_LegacyLocaleDetected(void)
234+
_Py_LegacyLocaleDetected(int warn)
235235
{
236236
#ifndef MS_WINDOWS
237+
if (!warn) {
238+
const char *locale_override = getenv("LC_ALL");
239+
if (locale_override != NULL && *locale_override != '\0') {
240+
/* Don't coerce C locale if the LC_ALL environment variable
241+
is set */
242+
return 0;
243+
}
244+
}
245+
237246
/* On non-Windows systems, the C locale is considered a legacy locale */
238247
/* XXX (ncoghlan): some platforms (notably Mac OS X) don't appear to treat
239248
* the POSIX locale as a simple alias for the C locale, so
@@ -257,7 +266,7 @@ static void
257266
emit_stderr_warning_for_legacy_locale(_PyRuntimeState *runtime)
258267
{
259268
const _PyPreConfig *preconfig = &runtime->preconfig;
260-
if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected()) {
269+
if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected(1)) {
261270
PySys_FormatStderr("%s", _C_LOCALE_WARNING);
262271
}
263272
}
@@ -292,7 +301,7 @@ static const char C_LOCALE_COERCION_WARNING[] =
292301
"Python detected LC_CTYPE=C: LC_CTYPE coerced to %.20s (set another locale "
293302
"or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior).\n";
294303

295-
static void
304+
static int
296305
_coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
297306
{
298307
const char *newloc = target->locale_name;
@@ -304,26 +313,28 @@ _coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target)
304313
if (setenv("LC_CTYPE", newloc, 1)) {
305314
fprintf(stderr,
306315
"Error setting LC_CTYPE, skipping C locale coercion\n");
307-
return;
316+
return 0;
308317
}
309318
if (warn) {
310319
fprintf(stderr, C_LOCALE_COERCION_WARNING, newloc);
311320
}
312321

313322
/* Reconfigure with the overridden environment variables */
314323
_Py_SetLocaleFromEnv(LC_ALL);
324+
return 1;
315325
}
316326
#endif
317327

318-
void
328+
int
319329
_Py_CoerceLegacyLocale(int warn)
320330
{
331+
int coerced = 0;
321332
#ifdef PY_COERCE_C_LOCALE
322333
char *oldloc = NULL;
323334

324335
oldloc = _PyMem_RawStrdup(setlocale(LC_CTYPE, NULL));
325336
if (oldloc == NULL) {
326-
return;
337+
return coerced;
327338
}
328339

329340
const char *locale_override = getenv("LC_ALL");
@@ -345,7 +356,7 @@ _Py_CoerceLegacyLocale(int warn)
345356
}
346357
#endif
347358
/* Successfully configured locale, so make it the default */
348-
_coerce_default_locale_settings(warn, target);
359+
coerced = _coerce_default_locale_settings(warn, target);
349360
goto done;
350361
}
351362
}
@@ -357,6 +368,7 @@ _Py_CoerceLegacyLocale(int warn)
357368
done:
358369
PyMem_RawFree(oldloc);
359370
#endif
371+
return coerced;
360372
}
361373

362374
/* _Py_SetLocaleFromEnv() is a wrapper around setlocale(category, "") to

0 commit comments

Comments
 (0)
0