[Python-checkins] bpo-46417: Clear _io module static objects at exit (GH-30807)

vstinner webhook-mailer at python.org
Sat Jan 22 17:22:38 EST 2022


https://github.com/python/cpython/commit/9c8e490b8f9e40a6fe9815be58bacaecab5369ee
commit: 9c8e490b8f9e40a6fe9815be58bacaecab5369ee
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022-01-22T23:22:20+01:00
summary:

bpo-46417: Clear _io module static objects at exit (GH-30807)

Add _PyIO_Fini() function, called by finalize_interp_clear(). It
clears static objects used by the _io extension module.

files:
M Modules/_io/_iomodule.c
M Python/pylifecycle.c

diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index b4743fbd5e04f..116688da5e7af 100644
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -666,6 +666,82 @@ struct PyModuleDef _PyIO_Module = {
     (freefunc)iomodule_free,
 };
 
+
+static PyTypeObject* static_types[] = {
+    // Base classes
+    &PyIOBase_Type,
+    &PyIncrementalNewlineDecoder_Type,
+
+    // PyIOBase_Type subclasses
+    &PyBufferedIOBase_Type,
+    &PyRawIOBase_Type,
+    &PyTextIOBase_Type,
+
+    // PyBufferedIOBase_Type(PyIOBase_Type) subclasses
+    &PyBytesIO_Type,
+    &PyBufferedReader_Type,
+    &PyBufferedWriter_Type,
+    &PyBufferedRWPair_Type,
+    &PyBufferedRandom_Type,
+
+    // PyRawIOBase_Type(PyIOBase_Type) subclasses
+    &PyFileIO_Type,
+    &_PyBytesIOBuffer_Type,
+#ifdef MS_WINDOWS
+    &PyWindowsConsoleIO_Type,
+#endif
+
+    // PyTextIOBase_Type(PyIOBase_Type) subclasses
+    &PyStringIO_Type,
+    &PyTextIOWrapper_Type,
+};
+
+
+void
+_PyIO_Fini(void)
+{
+    for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) {
+        PyTypeObject *exc = static_types[i];
+        _PyStaticType_Dealloc(exc);
+    }
+
+    /* Interned strings */
+#define CLEAR_INTERNED(name) \
+    Py_CLEAR(_PyIO_str_ ## name)
+
+    CLEAR_INTERNED(close);
+    CLEAR_INTERNED(closed);
+    CLEAR_INTERNED(decode);
+    CLEAR_INTERNED(encode);
+    CLEAR_INTERNED(fileno);
+    CLEAR_INTERNED(flush);
+    CLEAR_INTERNED(getstate);
+    CLEAR_INTERNED(isatty);
+    CLEAR_INTERNED(locale);
+    CLEAR_INTERNED(newlines);
+    CLEAR_INTERNED(peek);
+    CLEAR_INTERNED(read);
+    CLEAR_INTERNED(read1);
+    CLEAR_INTERNED(readable);
+    CLEAR_INTERNED(readall);
+    CLEAR_INTERNED(readinto);
+    CLEAR_INTERNED(readline);
+    CLEAR_INTERNED(reset);
+    CLEAR_INTERNED(seek);
+    CLEAR_INTERNED(seekable);
+    CLEAR_INTERNED(setstate);
+    CLEAR_INTERNED(tell);
+    CLEAR_INTERNED(truncate);
+    CLEAR_INTERNED(write);
+    CLEAR_INTERNED(writable);
+#undef CLEAR_INTERNED
+
+    Py_CLEAR(_PyIO_str_nl);
+    Py_CLEAR(_PyIO_empty_str);
+    Py_CLEAR(_PyIO_empty_bytes);
+}
+
+
 PyMODINIT_FUNC
 PyInit__io(void)
 {
@@ -676,11 +752,6 @@ PyInit__io(void)
     state = get_io_state(m);
     state->initialized = 0;
 
-#define ADD_TYPE(type) \
-    if (PyModule_AddType(m, type) < 0) {  \
-        goto fail; \
-    }
-
     /* DEFAULT_BUFFER_SIZE */
     if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
         goto fail;
@@ -702,57 +773,34 @@ PyInit__io(void)
                            (PyObject *) PyExc_BlockingIOError) < 0)
         goto fail;
 
-    /* Concrete base types of the IO ABCs.
-       (the ABCs themselves are declared through inheritance in io.py)
-    */
-    ADD_TYPE(&PyIOBase_Type);
-    ADD_TYPE(&PyRawIOBase_Type);
-    ADD_TYPE(&PyBufferedIOBase_Type);
-    ADD_TYPE(&PyTextIOBase_Type);
-
-    /* Implementation of concrete IO objects. */
-    /* FileIO */
+    // Set type base classes
     PyFileIO_Type.tp_base = &PyRawIOBase_Type;
-    ADD_TYPE(&PyFileIO_Type);
-
-    /* BytesIO */
     PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBytesIO_Type);
-    if (PyType_Ready(&_PyBytesIOBuffer_Type) < 0)
-        goto fail;
-
-    /* StringIO */
     PyStringIO_Type.tp_base = &PyTextIOBase_Type;
-    ADD_TYPE(&PyStringIO_Type);
-
 #ifdef MS_WINDOWS
-    /* WindowsConsoleIO */
     PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type;
-    ADD_TYPE(&PyWindowsConsoleIO_Type);
 #endif
-
-    /* BufferedReader */
     PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedReader_Type);
-
-    /* BufferedWriter */
     PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedWriter_Type);
-
-    /* BufferedRWPair */
     PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedRWPair_Type);
-
-    /* BufferedRandom */
     PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedRandom_Type);
-
-    /* TextIOWrapper */
     PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type;
-    ADD_TYPE(&PyTextIOWrapper_Type);
 
-    /* IncrementalNewlineDecoder */
-    ADD_TYPE(&PyIncrementalNewlineDecoder_Type);
+    // Add types
+    for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
+        PyTypeObject *type = static_types[i];
+        // Private type not exposed in the _io module
+        if (type == &_PyBytesIOBuffer_Type) {
+            if (PyType_Ready(type) < 0) {
+                goto fail;
+            }
+        }
+        else {
+            if (PyModule_AddType(m, type) < 0) {
+                goto fail;
+            }
+        }
+    }
 
     /* Interned strings */
 #define ADD_INTERNED(name) \
@@ -785,6 +833,7 @@ PyInit__io(void)
     ADD_INTERNED(truncate)
     ADD_INTERNED(write)
     ADD_INTERNED(writable)
+#undef ADD_INTERNED
 
     if (!_PyIO_str_nl &&
         !(_PyIO_str_nl = PyUnicode_InternFromString("\n")))
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 7fc9d3c94ce51..92c8ad079c5fb 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -29,6 +29,8 @@
 #include "pycore_typeobject.h"    // _PyTypes_InitTypes()
 #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
 
+extern void _PyIO_Fini(void);
+
 #include <locale.h>               // setlocale()
 #include <stdlib.h>               // getenv()
 
@@ -1702,6 +1704,10 @@ finalize_interp_clear(PyThreadState *tstate)
     /* Clear interpreter state and all thread states */
     _PyInterpreterState_Clear(tstate);
 
+    if (is_main_interp) {
+        _PyIO_Fini();
+    }
+
     /* Clear all loghooks */
     /* Both _PySys_Audit function and users still need PyObject, such as tuple.
        Call _PySys_ClearAuditHooks when PyObject available. */



More information about the Python-checkins mailing list