summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/warnings.h6
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/gcmodule.c10
-rw-r--r--Python/_warnings.c47
-rw-r--r--Python/import.c55
5 files changed, 96 insertions, 25 deletions
diff --git a/Include/warnings.h b/Include/warnings.h
index b7db681..5a7dfb1 100644
--- a/Include/warnings.h
+++ b/Include/warnings.h
@@ -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)
diff --git a/Misc/NEWS b/Misc/NEWS
index e1233c3..9c0be69 100644
--- 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.
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index c9c1252..4315d55 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -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)
);
}
diff --git a/Python/_warnings.c b/Python/_warnings.c
index f33e477..03e0c45 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -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.");
diff --git a/Python/import.c b/Python/import.c
index cd4fb78..1fbafec 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -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 */