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 */
89171void
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)
173255COPY_ATTR(coerce_c_locale_warn);
174256COPY_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);
181263182264COPY_WSTRLIST(argc, argv);
183265COPY_WSTRLIST(nwarnoption, warnoptions);
184266COPY_WSTRLIST(nxoption, xoptions);
185267COPY_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);
195277196278COPY_ATTR(isolated);
197279COPY_ATTR(site_import);
@@ -213,7 +295,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
213295COPY_ATTR(_frozen);
214296215297#undef COPY_ATTR
216-#undef COPY_STR_ATTR
298+#undef COPY_WSTR_ATTR
217299#undef COPY_WSTRLIST
218300return 0;
219301}
@@ -627,8 +709,6 @@ get_env_flag(_PyCoreConfig *config, int *flag, const char *name)
627709static _PyInitError
628710config_read_env_vars(_PyCoreConfig *config)
629711{
630-assert(config->use_environment > 0);
631-632712/* Get environment variables */
633713get_env_flag(config, &config->parser_debug, "PYTHONDEBUG");
634714get_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);
873954874955if (config->isolated > 0) {
875956config->use_environment = 0;
@@ -882,7 +963,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
882963 }
883964#endif
884965885-assert(config->use_environment >= 0);
886966if (config->use_environment) {
887967err = config_read_env_vars(config);
888968if (_Py_INIT_FAILED(err)) {
@@ -960,12 +1040,12 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
9601040if (config->utf8_mode < 0) {
9611041config->utf8_mode = 0;
9621042 }
963-if (config->_frozen < 0) {
964-config->_frozen = 0;
965- }
9661043if (config->argc < 0) {
9671044config->argc = 0;
9681045 }
96910461047+assert(config->coerce_c_locale >= 0);
1048+assert(config->use_environment >= 0);
1049+9701050return _Py_INIT_OK();
9711051}