Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 070cb3c

Browse files
committed
Issue #1545463: At shutdown, defer finalization of codec modules so that stderr remains usable.
(should fix Windows buildbot failures on test_gc)
1 parent d62a514 commit 070cb3c

5 files changed

Lines changed: 96 additions & 25 deletions

File tree

Include/warnings.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ PyAPI_FUNC(int) PyErr_WarnExplicit(
2525
const char *module, /* UTF-8 encoded string */
2626
PyObject *registry);
2727

28+
PyAPI_FUNC(int)
29+
PyErr_WarnExplicitFormat(PyObject *category,
30+
const char *filename, int lineno,
31+
const char *module, PyObject *registry,
32+
const char *format, ...);
33+
2834
/* DEPRECATED: Use PyErr_WarnEx() instead. */
2935
#ifndef Py_LIMITED_API
3036
#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #1545463: At shutdown, defer finalization of codec modules so
14+
that stderr remains usable.
15+
1316
- Issue #7330: Implement width and precision (ex: "%5.3s") for the format
1417
string of PyUnicode_FromFormat() function, original patch written by Ysj Ray.
1518

Modules/gcmodule.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,8 +1557,12 @@ _PyGC_DumpShutdownStats(void)
15571557
else
15581558
message = "gc: %zd uncollectable objects at " \
15591559
"shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them";
1560-
if (PyErr_WarnFormat(PyExc_ResourceWarning, 0, message,
1561-
PyList_GET_SIZE(garbage)) < 0)
1560+
/* PyErr_WarnFormat does too many things and we are at shutdown,
1561+
the warnings module's dependencies (e.g. linecache) may be gone
1562+
already. */
1563+
if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
1564+
"gc", NULL, message,
1565+
PyList_GET_SIZE(garbage)))
15621566
PyErr_WriteUnraisable(NULL);
15631567
if (debug & DEBUG_UNCOLLECTABLE) {
15641568
PyObject *repr = NULL, *bytes = NULL;
@@ -1567,7 +1571,7 @@ _PyGC_DumpShutdownStats(void)
15671571
PyErr_WriteUnraisable(garbage);
15681572
else {
15691573
PySys_WriteStderr(
1570-
" %s\n",
1574+
" %s\n",
15711575
PyBytes_AS_STRING(bytes)
15721576
);
15731577
}

Python/_warnings.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -800,8 +800,8 @@ PyErr_WarnExplicit(PyObject *category, const char *text,
800800
goto exit;
801801
if (module_str != NULL) {
802802
module = PyUnicode_FromString(module_str);
803-
if (module == NULL)
804-
goto exit;
803+
if (module == NULL)
804+
goto exit;
805805
}
806806

807807
if (category == NULL)
@@ -820,6 +820,49 @@ PyErr_WarnExplicit(PyObject *category, const char *text,
820820
return ret;
821821
}
822822

823+
int
824+
PyErr_WarnExplicitFormat(PyObject *category,
825+
const char *filename_str, int lineno,
826+
const char *module_str, PyObject *registry,
827+
const char *format, ...)
828+
{
829+
PyObject *message;
830+
PyObject *module = NULL;
831+
PyObject *filename = PyUnicode_DecodeFSDefault(filename_str);
832+
int ret = -1;
833+
va_list vargs;
834+
835+
if (filename == NULL)
836+
goto exit;
837+
if (module_str != NULL) {
838+
module = PyUnicode_FromString(module_str);
839+
if (module == NULL)
840+
goto exit;
841+
}
842+
843+
#ifdef HAVE_STDARG_PROTOTYPES
844+
va_start(vargs, format);
845+
#else
846+
va_start(vargs);
847+
#endif
848+
message = PyUnicode_FromFormatV(format, vargs);
849+
if (message != NULL) {
850+
PyObject *res;
851+
res = warn_explicit(category, message, filename, lineno,
852+
module, registry, NULL);
853+
Py_DECREF(message);
854+
if (res != NULL) {
855+
Py_DECREF(res);
856+
ret = 0;
857+
}
858+
}
859+
va_end(vargs);
860+
exit:
861+
Py_XDECREF(module);
862+
Py_XDECREF(filename);
863+
return ret;
864+
}
865+
823866

824867
PyDoc_STRVAR(warn_doc,
825868
"Issue a warning, or maybe ignore it or raise an exception.");

Python/import.c

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,30 @@ static char* sys_files[] = {
295295
NULL
296296
};
297297

298+
static int
299+
is_essential_module(PyObject *name)
300+
{
301+
Py_ssize_t name_len;
302+
char *name_str = PyUnicode_AsUTF8AndSize(name, &name_len);
303+
304+
if (name_str == NULL) {
305+
PyErr_Clear();
306+
return 0;
307+
}
308+
if (strcmp(name_str, "builtins") == 0)
309+
return 1;
310+
if (strcmp(name_str, "sys") == 0)
311+
return 1;
312+
/* These are all needed for stderr to still function */
313+
if (strcmp(name_str, "codecs") == 0)
314+
return 1;
315+
if (strcmp(name_str, "_codecs") == 0)
316+
return 1;
317+
if (strncmp(name_str, "encodings.", 10) == 0)
318+
return 1;
319+
return 0;
320+
}
321+
298322

299323
/* Un-initialize things, as good as we can */
300324

@@ -374,9 +398,7 @@ PyImport_Cleanup(void)
374398
if (value->ob_refcnt != 1)
375399
continue;
376400
if (PyUnicode_Check(key) && PyModule_Check(value)) {
377-
if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0)
378-
continue;
379-
if (PyUnicode_CompareWithASCIIString(key, "sys") == 0)
401+
if (is_essential_module(key))
380402
continue;
381403
if (Py_VerboseFlag)
382404
PySys_FormatStderr(
@@ -392,9 +414,7 @@ PyImport_Cleanup(void)
392414
pos = 0;
393415
while (PyDict_Next(modules, &pos, &key, &value)) {
394416
if (PyUnicode_Check(key) && PyModule_Check(value)) {
395-
if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0)
396-
continue;
397-
if (PyUnicode_CompareWithASCIIString(key, "sys") == 0)
417+
if (is_essential_module(key))
398418
continue;
399419
if (Py_VerboseFlag)
400420
PySys_FormatStderr("# cleanup[2] %U\n", key);
@@ -411,20 +431,15 @@ PyImport_Cleanup(void)
411431
machinery. */
412432
_PyGC_DumpShutdownStats();
413433

414-
/* Next, delete sys and builtins (in that order) */
415-
value = PyDict_GetItemString(modules, "sys");
416-
if (value != NULL && PyModule_Check(value)) {
417-
if (Py_VerboseFlag)
418-
PySys_WriteStderr("# cleanup sys\n");
419-
_PyModule_Clear(value);
420-
PyDict_SetItemString(modules, "sys", Py_None);
421-
}
422-
value = PyDict_GetItemString(modules, "builtins");
423-
if (value != NULL && PyModule_Check(value)) {
424-
if (Py_VerboseFlag)
425-
PySys_WriteStderr("# cleanup builtins\n");
426-
_PyModule_Clear(value);
427-
PyDict_SetItemString(modules, "builtins", Py_None);
434+
/* Next, delete all remaining modules */
435+
pos = 0;
436+
while (PyDict_Next(modules, &pos, &key, &value)) {
437+
if (PyUnicode_Check(key) && PyModule_Check(value)) {
438+
if (Py_VerboseFlag)
439+
PySys_FormatStderr("# cleanup[3] %U\n", key);
440+
_PyModule_Clear(value);
441+
PyDict_SetItem(modules, key, Py_None);
442+
}
428443
}
429444

430445
/* Finally, clear and delete the modules directory */

0 commit comments

Comments
 (0)