summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-01-22 22:22:20 (GMT)
committerGitHub <noreply@github.com>2022-01-22 22:22:20 (GMT)
commit9c8e490b8f9e40a6fe9815be58bacaecab5369ee (patch)
treec249f59c3fb54dc2efb8c38c53b617f72b02c67e
parent1626bf4ac7aef1244e6f886e63a31f7ed65fbd10 (diff)
downloadcpython-9c8e490b8f9e40a6fe9815be58bacaecab5369ee.zip
cpython-9c8e490b8f9e40a6fe9815be58bacaecab5369ee.tar.gz
cpython-9c8e490b8f9e40a6fe9815be58bacaecab5369ee.tar.bz2
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.
-rw-r--r--Modules/_io/_iomodule.c137
-rw-r--r--Python/pylifecycle.c6
2 files changed, 99 insertions, 44 deletions
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index b4743fb..116688d 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 7fc9d3c..92c8ad0 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. */