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.
This commit is contained in:
Victor Stinner 2022-01-22 23:22:20 +01:00 committed by GitHub
parent 1626bf4ac7
commit 9c8e490b8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 44 deletions

View file

@ -666,6 +666,82 @@ struct PyModuleDef _PyIO_Module = {
(freefunc)iomodule_free, (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 PyMODINIT_FUNC
PyInit__io(void) PyInit__io(void)
{ {
@ -676,11 +752,6 @@ PyInit__io(void)
state = get_io_state(m); state = get_io_state(m);
state->initialized = 0; state->initialized = 0;
#define ADD_TYPE(type) \
if (PyModule_AddType(m, type) < 0) { \
goto fail; \
}
/* DEFAULT_BUFFER_SIZE */ /* DEFAULT_BUFFER_SIZE */
if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
goto fail; goto fail;
@ -702,57 +773,34 @@ PyInit__io(void)
(PyObject *) PyExc_BlockingIOError) < 0) (PyObject *) PyExc_BlockingIOError) < 0)
goto fail; goto fail;
/* Concrete base types of the IO ABCs. // Set type base classes
(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 */
PyFileIO_Type.tp_base = &PyRawIOBase_Type; PyFileIO_Type.tp_base = &PyRawIOBase_Type;
ADD_TYPE(&PyFileIO_Type);
/* BytesIO */
PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type; 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; PyStringIO_Type.tp_base = &PyTextIOBase_Type;
ADD_TYPE(&PyStringIO_Type);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
/* WindowsConsoleIO */
PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type;
ADD_TYPE(&PyWindowsConsoleIO_Type);
#endif #endif
/* BufferedReader */
PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type; PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedReader_Type);
/* BufferedWriter */
PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type; PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedWriter_Type);
/* BufferedRWPair */
PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type; PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedRWPair_Type);
/* BufferedRandom */
PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type; PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedRandom_Type);
/* TextIOWrapper */
PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type; PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type;
ADD_TYPE(&PyTextIOWrapper_Type);
/* IncrementalNewlineDecoder */ // Add types
ADD_TYPE(&PyIncrementalNewlineDecoder_Type); 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 */ /* Interned strings */
#define ADD_INTERNED(name) \ #define ADD_INTERNED(name) \
@ -785,6 +833,7 @@ PyInit__io(void)
ADD_INTERNED(truncate) ADD_INTERNED(truncate)
ADD_INTERNED(write) ADD_INTERNED(write)
ADD_INTERNED(writable) ADD_INTERNED(writable)
#undef ADD_INTERNED
if (!_PyIO_str_nl && if (!_PyIO_str_nl &&
!(_PyIO_str_nl = PyUnicode_InternFromString("\n"))) !(_PyIO_str_nl = PyUnicode_InternFromString("\n")))

View file

@ -29,6 +29,8 @@
#include "pycore_typeobject.h" // _PyTypes_InitTypes() #include "pycore_typeobject.h" // _PyTypes_InitTypes()
#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
extern void _PyIO_Fini(void);
#include <locale.h> // setlocale() #include <locale.h> // setlocale()
#include <stdlib.h> // getenv() #include <stdlib.h> // getenv()
@ -1702,6 +1704,10 @@ finalize_interp_clear(PyThreadState *tstate)
/* Clear interpreter state and all thread states */ /* Clear interpreter state and all thread states */
_PyInterpreterState_Clear(tstate); _PyInterpreterState_Clear(tstate);
if (is_main_interp) {
_PyIO_Fini();
}
/* Clear all loghooks */ /* Clear all loghooks */
/* Both _PySys_Audit function and users still need PyObject, such as tuple. /* Both _PySys_Audit function and users still need PyObject, such as tuple.
Call _PySys_ClearAuditHooks when PyObject available. */ Call _PySys_ClearAuditHooks when PyObject available. */