]> granicus.if.org Git - python/commitdiff
Issue #1545463: At shutdown, defer finalization of codec modules so that stderr remai...
authorAntoine Pitrou <solipsis@pitrou.net>
Wed, 8 May 2013 11:23:25 +0000 (13:23 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Wed, 8 May 2013 11:23:25 +0000 (13:23 +0200)
(should fix Windows buildbot failures on test_gc)

Include/warnings.h
Misc/NEWS
Modules/gcmodule.c
Python/_warnings.c
Python/import.c

index b7db681cc41fe007d2e95e439b59bf6ba828d1b7..5a7dfb1bb24b320dea3d5357c06924f80e687da1 100644 (file)
@@ -25,6 +25,12 @@ PyAPI_FUNC(int) PyErr_WarnExplicit(
     const char *module,         /* UTF-8 encoded string */
     PyObject *registry);
 
+PyAPI_FUNC(int)
+PyErr_WarnExplicitFormat(PyObject *category,
+                         const char *filename, int lineno,
+                         const char *module, PyObject *registry,
+                         const char *format, ...);
+
 /* DEPRECATED: Use PyErr_WarnEx() instead. */
 #ifndef Py_LIMITED_API
 #define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1)
index e1233c3fac814955fe616174eb24267dbd675f77..9c0be6926947998d1702293be8c83c85cdfea393 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
 Core and Builtins
 -----------------
 
+- Issue #1545463: At shutdown, defer finalization of codec modules so
+  that stderr remains usable.
+
 - Issue #7330: Implement width and precision (ex: "%5.3s") for the format
   string of PyUnicode_FromFormat() function, original patch written by Ysj Ray.
 
index c9c1252d345e69064d81c23798fa3b8a715a1dfc..4315d55dcdb9c19adafb1082fdf6cbf660ff0663 100644 (file)
@@ -1557,8 +1557,12 @@ _PyGC_DumpShutdownStats(void)
         else
             message = "gc: %zd uncollectable objects at " \
                 "shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them";
-        if (PyErr_WarnFormat(PyExc_ResourceWarning, 0, message,
-                             PyList_GET_SIZE(garbage)) < 0)
+        /* PyErr_WarnFormat does too many things and we are at shutdown,
+           the warnings module's dependencies (e.g. linecache) may be gone
+           already. */
+        if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
+                                     "gc", NULL, message,
+                                     PyList_GET_SIZE(garbage)))
             PyErr_WriteUnraisable(NULL);
         if (debug & DEBUG_UNCOLLECTABLE) {
             PyObject *repr = NULL, *bytes = NULL;
@@ -1567,7 +1571,7 @@ _PyGC_DumpShutdownStats(void)
                 PyErr_WriteUnraisable(garbage);
             else {
                 PySys_WriteStderr(
-                    "    %s\n",
+                    "      %s\n",
                     PyBytes_AS_STRING(bytes)
                     );
             }
index f33e477ad7bd7905eb43c4192106d49ca8fad75e..03e0c4545ae3947f3e131bfc599ed15f0d76f826 100644 (file)
@@ -800,8 +800,8 @@ PyErr_WarnExplicit(PyObject *category, const char *text,
         goto exit;
     if (module_str != NULL) {
         module = PyUnicode_FromString(module_str);
-            if (module == NULL)
-                goto exit;
+        if (module == NULL)
+            goto exit;
     }
 
     if (category == NULL)
@@ -820,6 +820,49 @@ PyErr_WarnExplicit(PyObject *category, const char *text,
     return ret;
 }
 
+int
+PyErr_WarnExplicitFormat(PyObject *category,
+                         const char *filename_str, int lineno,
+                         const char *module_str, PyObject *registry,
+                         const char *format, ...)
+{
+    PyObject *message;
+    PyObject *module = NULL;
+    PyObject *filename = PyUnicode_DecodeFSDefault(filename_str);
+    int ret = -1;
+    va_list vargs;
+
+    if (filename == NULL)
+        goto exit;
+    if (module_str != NULL) {
+        module = PyUnicode_FromString(module_str);
+        if (module == NULL)
+            goto exit;
+    }
+
+#ifdef HAVE_STDARG_PROTOTYPES
+    va_start(vargs, format);
+#else
+    va_start(vargs);
+#endif
+    message = PyUnicode_FromFormatV(format, vargs);
+    if (message != NULL) {
+        PyObject *res;
+        res = warn_explicit(category, message, filename, lineno,
+                            module, registry, NULL);
+        Py_DECREF(message);
+        if (res != NULL) {
+            Py_DECREF(res);
+            ret = 0;
+        }
+    }
+    va_end(vargs);
+exit:
+    Py_XDECREF(module);
+    Py_XDECREF(filename);
+    return ret;
+}
+
 
 PyDoc_STRVAR(warn_doc,
 "Issue a warning, or maybe ignore it or raise an exception.");
index cd4fb788a10ad98ef6504f4ad846c6e017265c87..1fbafecc1b70b62ed24035dfe99758fd25c285d1 100644 (file)
@@ -295,6 +295,30 @@ static char* sys_files[] = {
     NULL
 };
 
+static int
+is_essential_module(PyObject *name)
+{
+    Py_ssize_t name_len;
+    char *name_str = PyUnicode_AsUTF8AndSize(name, &name_len);
+
+    if (name_str == NULL) {
+        PyErr_Clear();
+        return 0;
+    }
+    if (strcmp(name_str, "builtins") == 0)
+        return 1;
+    if (strcmp(name_str, "sys") == 0)
+        return 1;
+    /* These are all needed for stderr to still function */
+    if (strcmp(name_str, "codecs") == 0)
+        return 1;
+    if (strcmp(name_str, "_codecs") == 0)
+        return 1;
+    if (strncmp(name_str, "encodings.", 10) == 0)
+        return 1;
+    return 0;
+}
+
 
 /* Un-initialize things, as good as we can */
 
@@ -374,9 +398,7 @@ PyImport_Cleanup(void)
             if (value->ob_refcnt != 1)
                 continue;
             if (PyUnicode_Check(key) && PyModule_Check(value)) {
-                if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0)
-                    continue;
-                if (PyUnicode_CompareWithASCIIString(key, "sys") == 0)
+                if (is_essential_module(key))
                     continue;
                 if (Py_VerboseFlag)
                     PySys_FormatStderr(
@@ -392,9 +414,7 @@ PyImport_Cleanup(void)
     pos = 0;
     while (PyDict_Next(modules, &pos, &key, &value)) {
         if (PyUnicode_Check(key) && PyModule_Check(value)) {
-            if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0)
-                continue;
-            if (PyUnicode_CompareWithASCIIString(key, "sys") == 0)
+            if (is_essential_module(key))
                 continue;
             if (Py_VerboseFlag)
                 PySys_FormatStderr("# cleanup[2] %U\n", key);
@@ -411,20 +431,15 @@ PyImport_Cleanup(void)
        machinery. */
     _PyGC_DumpShutdownStats();
 
-    /* Next, delete sys and builtins (in that order) */
-    value = PyDict_GetItemString(modules, "sys");
-    if (value != NULL && PyModule_Check(value)) {
-        if (Py_VerboseFlag)
-            PySys_WriteStderr("# cleanup sys\n");
-        _PyModule_Clear(value);
-        PyDict_SetItemString(modules, "sys", Py_None);
-    }
-    value = PyDict_GetItemString(modules, "builtins");
-    if (value != NULL && PyModule_Check(value)) {
-        if (Py_VerboseFlag)
-            PySys_WriteStderr("# cleanup builtins\n");
-        _PyModule_Clear(value);
-        PyDict_SetItemString(modules, "builtins", Py_None);
+    /* Next, delete all remaining modules */
+    pos = 0;
+    while (PyDict_Next(modules, &pos, &key, &value)) {
+        if (PyUnicode_Check(key) && PyModule_Check(value)) {
+            if (Py_VerboseFlag)
+                PySys_FormatStderr("# cleanup[3] %U\n", key);
+            _PyModule_Clear(value);
+            PyDict_SetItem(modules, key, Py_None);
+        }
     }
 
     /* Finally, clear and delete the modules directory */