Skip to content

Commit 4fffd38

Browse files
authored
bpo-36142: _PyPreConfig_Read() sets LC_CTYPE (GH-12188)
* _PyPreConfig_Read() now sets temporarily LC_CTYPE to the user preferred locale, as _PyPreConfig_Write() will do permanentely. * Fix _PyCoreConfig_Clear(): clear run_xxx attributes * _Py_SetArgcArgv() doesn't have to be exported * _PyCoreConfig_SetGlobalConfig() no longer applies preconfig
1 parent c656e25 commit 4fffd38

File tree

4 files changed

+78
-47
lines changed

4 files changed

+78
-47
lines changed

Include/internal/pycore_coreconfig.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ PyAPI_FUNC(_PyInitError) _PyArgv_Decode(const _PyArgv *args,
3232
/* --- Py_GetArgcArgv() helpers ----------------------------------- */
3333

3434
PyAPI_FUNC(void) _Py_ClearArgcArgv(void);
35-
PyAPI_FUNC(int) _Py_SetArgcArgv(int argc, wchar_t * const *argv);
3635

3736
/* --- _PyPreConfig ----------------------------------------------- */
3837

Python/coreconfig.c

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ _Py_ClearArgcArgv(void)
387387
}
388388

389389

390-
int
390+
static int
391391
_Py_SetArgcArgv(int argc, wchar_t * const *argv)
392392
{
393393
int res;
@@ -473,6 +473,9 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
473473
CLEAR(config->filesystem_errors);
474474
CLEAR(config->stdio_encoding);
475475
CLEAR(config->stdio_errors);
476+
CLEAR(config->run_command);
477+
CLEAR(config->run_module);
478+
CLEAR(config->run_filename);
476479
#undef CLEAR
477480
#undef CLEAR_WSTRLIST
478481
}
@@ -677,8 +680,6 @@ _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config)
677680
void
678681
_PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config)
679682
{
680-
_PyPreConfig_SetGlobalConfig(&config->preconfig);
681-
682683
#define COPY_FLAG(ATTR, VAR) \
683684
if (config->ATTR != -1) { \
684685
VAR = config->ATTR; \
@@ -812,6 +813,7 @@ config_init_executable(_PyCoreConfig *config)
812813
return _Py_INIT_OK();
813814
}
814815

816+
815817
static const wchar_t*
816818
config_get_xoption(const _PyCoreConfig *config, wchar_t *name)
817819
{
@@ -897,35 +899,34 @@ config_wstr_to_int(const wchar_t *wstr, int *result)
897899
static _PyInitError
898900
config_read_env_vars(_PyCoreConfig *config)
899901
{
900-
#define get_env_flag(CONFIG, ATTR, NAME) \
901-
_Py_get_env_flag(&(CONFIG)->preconfig, (ATTR), (NAME))
902+
_PyPreConfig *preconfig = &config->preconfig;
902903

903904
/* Get environment variables */
904-
get_env_flag(config, &config->parser_debug, "PYTHONDEBUG");
905-
get_env_flag(config, &config->verbose, "PYTHONVERBOSE");
906-
get_env_flag(config, &config->optimization_level, "PYTHONOPTIMIZE");
907-
get_env_flag(config, &config->inspect, "PYTHONINSPECT");
905+
_Py_get_env_flag(preconfig, &config->parser_debug, "PYTHONDEBUG");
906+
_Py_get_env_flag(preconfig, &config->verbose, "PYTHONVERBOSE");
907+
_Py_get_env_flag(preconfig, &config->optimization_level, "PYTHONOPTIMIZE");
908+
_Py_get_env_flag(preconfig, &config->inspect, "PYTHONINSPECT");
908909

909910
int dont_write_bytecode = 0;
910-
get_env_flag(config, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE");
911+
_Py_get_env_flag(preconfig, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE");
911912
if (dont_write_bytecode) {
912913
config->write_bytecode = 0;
913914
}
914915

915916
int no_user_site_directory = 0;
916-
get_env_flag(config, &no_user_site_directory, "PYTHONNOUSERSITE");
917+
_Py_get_env_flag(preconfig, &no_user_site_directory, "PYTHONNOUSERSITE");
917918
if (no_user_site_directory) {
918919
config->user_site_directory = 0;
919920
}
920921

921922
int unbuffered_stdio = 0;
922-
get_env_flag(config, &unbuffered_stdio, "PYTHONUNBUFFERED");
923+
_Py_get_env_flag(preconfig, &unbuffered_stdio, "PYTHONUNBUFFERED");
923924
if (unbuffered_stdio) {
924925
config->buffered_stdio = 0;
925926
}
926927

927928
#ifdef MS_WINDOWS
928-
get_env_flag(config, &config->legacy_windows_stdio,
929+
_Py_get_env_flag(preconfig, &config->legacy_windows_stdio,
929930
"PYTHONLEGACYWINDOWSSTDIO");
930931
#endif
931932

@@ -952,8 +953,6 @@ config_read_env_vars(_PyCoreConfig *config)
952953
}
953954

954955
return _Py_INIT_OK();
955-
956-
#undef get_env_flag
957956
}
958957

959958

@@ -1333,10 +1332,7 @@ _PyCoreConfig_ReadPreConfig(_PyCoreConfig *config)
13331332
}
13341333

13351334

1336-
/* Read the configuration into _PyCoreConfig and initialize the LC_CTYPE
1337-
locale: enable UTF-8 mode (PEP 540) and/or coerce the C locale (PEP 538).
1338-
1339-
Read the configuration from:
1335+
/* Read the configuration into _PyCoreConfig from:
13401336
13411337
* Environment variables
13421338
* Py_xxx global configuration variables
@@ -1497,8 +1493,6 @@ config_init_stdio(const _PyCoreConfig *config)
14971493

14981494
/* Write the configuration:
14991495
1500-
- coerce the LC_CTYPE locale (PEP 538)
1501-
- UTF-8 mode (PEP 540)
15021496
- set Py_xxx global configuration variables
15031497
- initialize C standard streams (stdin, stdout, stderr) */
15041498
void
@@ -2110,10 +2104,7 @@ config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
21102104
}
21112105

21122106

2113-
/* Read the configuration into _PyCoreConfig and initialize the LC_CTYPE
2114-
locale: enable UTF-8 mode (PEP 540) and/or coerce the C locale (PEP 538).
2115-
2116-
Read the configuration from:
2107+
/* Read the configuration into _PyCoreConfig from:
21172108
21182109
* Command line arguments
21192110
* Environment variables

Python/preconfig.c

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -472,10 +472,50 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
472472
}
473473

474474

475+
static _PyInitError
476+
get_ctype_locale(char **locale_p)
477+
{
478+
const char *loc = setlocale(LC_CTYPE, NULL);
479+
if (loc == NULL) {
480+
return _Py_INIT_ERR("failed to LC_CTYPE locale");
481+
}
482+
483+
char *copy = _PyMem_RawStrdup(loc);
484+
if (copy == NULL) {
485+
return _Py_INIT_NO_MEMORY();
486+
}
487+
488+
*locale_p = copy;
489+
return _Py_INIT_OK();
490+
}
491+
492+
493+
/* Read the configuration from:
494+
495+
- environment variables
496+
- Py_xxx global configuration variables
497+
- the LC_CTYPE locale
498+
499+
See _PyPreConfig_ReadFromArgv() to parse also command line arguments. */
475500
_PyInitError
476501
_PyPreConfig_Read(_PyPreConfig *config)
477502
{
478-
return preconfig_read(config, NULL);
503+
_PyInitError err;
504+
char *old_loc;
505+
506+
err = get_ctype_locale(&old_loc);
507+
if (_Py_INIT_FAILED(err)) {
508+
return err;
509+
}
510+
511+
/* Set LC_CTYPE to the user preferred locale */
512+
_Py_SetLocaleFromEnv(LC_CTYPE);
513+
514+
err = preconfig_read(config, NULL);
515+
516+
setlocale(LC_CTYPE, old_loc);
517+
518+
return err;
479519
}
480520

481521

@@ -604,7 +644,14 @@ preconfig_from_argv(_PyPreConfig *config, const _PyArgv *args)
604644
}
605645

606646

607-
/* Read the preconfiguration. */
647+
/* Read the configuration from:
648+
649+
- command line arguments
650+
- environment variables
651+
- Py_xxx global configuration variables
652+
- the LC_CTYPE locale
653+
654+
See _PyPreConfig_ReadFromArgv() to parse also command line arguments. */
608655
_PyInitError
609656
_PyPreConfig_ReadFromArgv(_PyPreConfig *config, const _PyArgv *args)
610657
{
@@ -624,15 +671,8 @@ _PyPreConfig_ReadFromArgv(_PyPreConfig *config, const _PyArgv *args)
624671
int locale_coerced = 0;
625672
int loops = 0;
626673

627-
/* copy LC_CTYPE locale */
628-
const char *loc = setlocale(LC_CTYPE, NULL);
629-
if (loc == NULL) {
630-
err = _Py_INIT_ERR("failed to LC_CTYPE locale");
631-
goto done;
632-
}
633-
init_ctype_locale = _PyMem_RawStrdup(loc);
634-
if (init_ctype_locale == NULL) {
635-
err = _Py_INIT_NO_MEMORY();
674+
err = get_ctype_locale(&init_ctype_locale);
675+
if (_Py_INIT_FAILED(err)) {
636676
goto done;
637677
}
638678

@@ -767,15 +807,23 @@ _PyPreConfig_SetAllocator(_PyPreConfig *config)
767807
}
768808

769809

770-
/* Write the pre-configuration.
810+
/* Write the pre-configuration:
811+
812+
- set the memory allocators
813+
- set Py_xxx global configuration variables
814+
- set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
815+
(PEP 540)
771816
772817
If the memory allocator is changed, config is re-allocated with new
773-
allocator. So calling _PyPreConfig_Clear(config) is safe after this call. */
818+
allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
819+
820+
Do nothing if called after Py_Initialize(): ignore the new
821+
pre-configuration. */
774822
_PyInitError
775823
_PyPreConfig_Write(_PyPreConfig *config)
776824
{
777825
if (_PyRuntime.core_initialized) {
778-
/* bpo-34008: Calling Py_Main() after Py_Initialize() ignores
826+
/* bpo-34008: Calling this functions after Py_Initialize() ignores
779827
the new configuration. */
780828
return _Py_INIT_OK();
781829
}

Python/pylifecycle.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -716,9 +716,6 @@ _Py_InitializeCore_impl(PyInterpreterState **interp_p,
716716
static _PyInitError
717717
pyinit_preconfig(_PyPreConfig *preconfig, const _PyPreConfig *src_preconfig)
718718
{
719-
/* Set LC_CTYPE to the user preferred locale */
720-
_Py_SetLocaleFromEnv(LC_CTYPE);
721-
722719
if (_PyPreConfig_Copy(preconfig, src_preconfig) < 0) {
723720
return _Py_INIT_ERR("failed to copy pre config");
724721
}
@@ -736,10 +733,6 @@ static _PyInitError
736733
pyinit_coreconfig(_PyCoreConfig *config, const _PyCoreConfig *src_config,
737734
PyInterpreterState **interp_p)
738735
{
739-
740-
/* Set LC_CTYPE to the user preferred locale */
741-
_Py_SetLocaleFromEnv(LC_CTYPE);
742-
743736
if (_PyCoreConfig_Copy(config, src_config) < 0) {
744737
return _Py_INIT_ERR("failed to copy core config");
745738
}

0 commit comments

Comments
 (0)