bpo-34485: Add _Py_ClearStandardStreamEncoding() (GH-8982) · python/cpython@124b9eb

@@ -85,6 +85,88 @@ _Py_wstrlist_copy(int len, wchar_t **list)

8585

}

8686878788+

/* Helper to allow an embedding application to override the normal

89+

* mechanism that attempts to figure out an appropriate IO encoding

90+

*/

91+92+

char *_Py_StandardStreamEncoding = NULL;

93+

char *_Py_StandardStreamErrors = NULL;

94+95+

int

96+

Py_SetStandardStreamEncoding(const char *encoding, const char *errors)

97+

{

98+

if (Py_IsInitialized()) {

99+

/* This is too late to have any effect */

100+

return -1;

101+

}

102+103+

int res = 0;

104+105+

/* Py_SetStandardStreamEncoding() can be called before Py_Initialize(),

106+

but Py_Initialize() can change the allocator. Use a known allocator

107+

to be able to release the memory later. */

108+

PyMemAllocatorEx old_alloc;

109+

_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

110+111+

/* Can't call PyErr_NoMemory() on errors, as Python hasn't been

112+

* initialised yet.

113+

*

114+

* However, the raw memory allocators are initialised appropriately

115+

* as C static variables, so _PyMem_RawStrdup is OK even though

116+

* Py_Initialize hasn't been called yet.

117+

*/

118+

if (encoding) {

119+

_Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding);

120+

if (!_Py_StandardStreamEncoding) {

121+

res = -2;

122+

goto done;

123+

}

124+

}

125+

if (errors) {

126+

_Py_StandardStreamErrors = _PyMem_RawStrdup(errors);

127+

if (!_Py_StandardStreamErrors) {

128+

if (_Py_StandardStreamEncoding) {

129+

PyMem_RawFree(_Py_StandardStreamEncoding);

130+

}

131+

res = -3;

132+

goto done;

133+

}

134+

}

135+

#ifdef MS_WINDOWS

136+

if (_Py_StandardStreamEncoding) {

137+

/* Overriding the stream encoding implies legacy streams */

138+

Py_LegacyWindowsStdioFlag = 1;

139+

}

140+

#endif

141+142+

done:

143+

PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

144+145+

return res;

146+

}

147+148+149+

void

150+

_Py_ClearStandardStreamEncoding(void)

151+

{

152+

/* Use the same allocator than Py_SetStandardStreamEncoding() */

153+

PyMemAllocatorEx old_alloc;

154+

_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

155+156+

/* We won't need them anymore. */

157+

if (_Py_StandardStreamEncoding) {

158+

PyMem_RawFree(_Py_StandardStreamEncoding);

159+

_Py_StandardStreamEncoding = NULL;

160+

}

161+

if (_Py_StandardStreamErrors) {

162+

PyMem_RawFree(_Py_StandardStreamErrors);

163+

_Py_StandardStreamErrors = NULL;

164+

}

165+166+

PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

167+

}

168+169+88170

/* Free memory allocated in config, but don't clear all attributes */

89171

void

90172

_PyCoreConfig_Clear(_PyCoreConfig *config)

@@ -134,7 +216,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)

134216

_PyCoreConfig_Clear(config);

135217136218

#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR

137-

#define COPY_STR_ATTR(ATTR) \

219+

#define COPY_WSTR_ATTR(ATTR) \

138220

do { \

139221

if (config2->ATTR != NULL) { \

140222

config->ATTR = _PyMem_RawWcsdup(config2->ATTR); \

@@ -173,25 +255,25 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)

173255

COPY_ATTR(coerce_c_locale_warn);

174256

COPY_ATTR(utf8_mode);

175257176-

COPY_STR_ATTR(pycache_prefix);

177-

COPY_STR_ATTR(module_search_path_env);

178-

COPY_STR_ATTR(home);

179-

COPY_STR_ATTR(program_name);

180-

COPY_STR_ATTR(program);

258+

COPY_WSTR_ATTR(pycache_prefix);

259+

COPY_WSTR_ATTR(module_search_path_env);

260+

COPY_WSTR_ATTR(home);

261+

COPY_WSTR_ATTR(program_name);

262+

COPY_WSTR_ATTR(program);

181263182264

COPY_WSTRLIST(argc, argv);

183265

COPY_WSTRLIST(nwarnoption, warnoptions);

184266

COPY_WSTRLIST(nxoption, xoptions);

185267

COPY_WSTRLIST(nmodule_search_path, module_search_paths);

186268187-

COPY_STR_ATTR(executable);

188-

COPY_STR_ATTR(prefix);

189-

COPY_STR_ATTR(base_prefix);

190-

COPY_STR_ATTR(exec_prefix);

269+

COPY_WSTR_ATTR(executable);

270+

COPY_WSTR_ATTR(prefix);

271+

COPY_WSTR_ATTR(base_prefix);

272+

COPY_WSTR_ATTR(exec_prefix);

191273

#ifdef MS_WINDOWS

192-

COPY_STR_ATTR(dll_path);

274+

COPY_WSTR_ATTR(dll_path);

193275

#endif

194-

COPY_STR_ATTR(base_exec_prefix);

276+

COPY_WSTR_ATTR(base_exec_prefix);

195277196278

COPY_ATTR(isolated);

197279

COPY_ATTR(site_import);

@@ -213,7 +295,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)

213295

COPY_ATTR(_frozen);

214296215297

#undef COPY_ATTR

216-

#undef COPY_STR_ATTR

298+

#undef COPY_WSTR_ATTR

217299

#undef COPY_WSTRLIST

218300

return 0;

219301

}

@@ -627,8 +709,6 @@ get_env_flag(_PyCoreConfig *config, int *flag, const char *name)

627709

static _PyInitError

628710

config_read_env_vars(_PyCoreConfig *config)

629711

{

630-

assert(config->use_environment > 0);

631-632712

/* Get environment variables */

633713

get_env_flag(config, &config->parser_debug, "PYTHONDEBUG");

634714

get_env_flag(config, &config->verbose, "PYTHONVERBOSE");

@@ -870,6 +950,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)

870950

_PyInitError err;

871951872952

_PyCoreConfig_GetGlobalConfig(config);

953+

assert(config->use_environment >= 0);

873954874955

if (config->isolated > 0) {

875956

config->use_environment = 0;

@@ -882,7 +963,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config)

882963

}

883964

#endif

884965885-

assert(config->use_environment >= 0);

886966

if (config->use_environment) {

887967

err = config_read_env_vars(config);

888968

if (_Py_INIT_FAILED(err)) {

@@ -960,12 +1040,12 @@ _PyCoreConfig_Read(_PyCoreConfig *config)

9601040

if (config->utf8_mode < 0) {

9611041

config->utf8_mode = 0;

9621042

}

963-

if (config->_frozen < 0) {

964-

config->_frozen = 0;

965-

}

9661043

if (config->argc < 0) {

9671044

config->argc = 0;

9681045

}

96910461047+

assert(config->coerce_c_locale >= 0);

1048+

assert(config->use_environment >= 0);

1049+9701050

return _Py_INIT_OK();

9711051

}