summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlend E. Aasland <erlend.aasland@protonmail.com>2023-05-15 11:26:27 +0200
committerGitHub <noreply@github.com>2023-05-15 09:26:27 +0000
commit186bf39f5c6003912e4f445430c504db51b9a743 (patch)
tree8f1fc65f9f578bdc846d91f5dbb4c27d94927348
parent35bf0916d913b83cf1883b76e67ad8b1c9a25bbe (diff)
downloadcpython-git-186bf39f5c6003912e4f445430c504db51b9a743.tar.gz
gh-101819: Isolate `_io` (#101948)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org>
-rw-r--r--Lib/test/test_io.py7
-rw-r--r--Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst2
-rw-r--r--Modules/_io/_iomodule.c138
-rw-r--r--Modules/_io/_iomodule.h15
-rw-r--r--Modules/_io/bufferedio.c116
-rw-r--r--Modules/_io/bytesio.c2
-rw-r--r--Modules/_io/fileio.c4
-rw-r--r--Modules/_io/iobase.c176
-rw-r--r--Modules/_io/stringio.c11
-rw-r--r--Modules/_io/textio.c80
-rw-r--r--Modules/_io/winconsoleio.c2
-rw-r--r--Python/pylifecycle.c10
-rw-r--r--Tools/c-analyzer/cpython/globals-to-fix.tsv4
13 files changed, 205 insertions, 362 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 9bcc92a40c..cc16804fe2 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -4242,6 +4242,7 @@ class MiscIOTest(unittest.TestCase):
def test_pickling(self):
# Pickling file objects is forbidden
+ msg = "cannot pickle"
for kwargs in [
{"mode": "w"},
{"mode": "wb"},
@@ -4256,8 +4257,10 @@ class MiscIOTest(unittest.TestCase):
if "b" not in kwargs["mode"]:
kwargs["encoding"] = "utf-8"
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
- with self.open(os_helper.TESTFN, **kwargs) as f:
- self.assertRaises(TypeError, pickle.dumps, f, protocol)
+ with self.subTest(protocol=protocol, kwargs=kwargs):
+ with self.open(os_helper.TESTFN, **kwargs) as f:
+ with self.assertRaisesRegex(TypeError, msg):
+ pickle.dumps(f, protocol)
@unittest.skipIf(
support.is_emscripten, "fstat() of a pipe fd is not supported"
diff --git a/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst b/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst
new file mode 100644
index 0000000000..4a73bbf32b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst
@@ -0,0 +1,2 @@
+Isolate the :mod:`io` extension module by applying :pep:`687`. Patch by
+Kumar Aditya, Victor Stinner, and Erlend E. Aasland.
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index 2457cb1240..7b06c1bee5 100644
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -561,25 +561,9 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err)
return result;
}
-_PyIO_State *
-_PyIO_get_module_state(void)
-{
- PyObject *mod = PyState_FindModule(&_PyIO_Module);
- _PyIO_State *state;
- if (mod == NULL || (state = get_io_state(mod)) == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "could not find io module state "
- "(interpreter shutdown?)");
- return NULL;
- }
- return state;
-}
-
static int
iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
_PyIO_State *state = get_io_state(mod);
- if (!state->initialized)
- return 0;
Py_VISIT(state->unsupported_operation);
Py_VISIT(state->PyIOBase_Type);
@@ -606,8 +590,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
static int
iomodule_clear(PyObject *mod) {
_PyIO_State *state = get_io_state(mod);
- if (!state->initialized)
- return 0;
Py_CLEAR(state->unsupported_operation);
Py_CLEAR(state->PyIOBase_Type);
@@ -652,115 +634,57 @@ static PyMethodDef module_methods[] = {
{NULL, NULL}
};
-struct PyModuleDef _PyIO_Module = {
- PyModuleDef_HEAD_INIT,
- "io",
- module_doc,
- sizeof(_PyIO_State),
- module_methods,
- NULL,
- iomodule_traverse,
- iomodule_clear,
- (freefunc)iomodule_free,
-};
-
-
-static PyTypeObject* static_types[] = {
- // Base classes
- &PyIOBase_Type,
-
- // PyIOBase_Type subclasses
- &PyBufferedIOBase_Type,
- &PyRawIOBase_Type,
- &PyTextIOBase_Type,
-};
-
-
-PyStatus
-_PyIO_InitTypes(PyInterpreterState *interp)
-{
- for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
- PyTypeObject *type = static_types[i];
- if (_PyStaticType_InitBuiltin(interp, type) < 0) {
- return _PyStatus_ERR("Can't initialize builtin type");
- }
- }
-
- return _PyStatus_OK();
-}
-
-void
-_PyIO_FiniTypes(PyInterpreterState *interp)
-{
- // Deallocate types in the reverse order to deallocate subclasses before
- // their base classes.
- for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) {
- PyTypeObject *type = static_types[i];
- _PyStaticType_Dealloc(interp, type);
- }
-}
-
#define ADD_TYPE(module, type, spec, base) \
do { \
type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \
(PyObject *)base); \
if (type == NULL) { \
- goto fail; \
+ return -1; \
} \
if (PyModule_AddType(module, type) < 0) { \
- goto fail; \
+ return -1; \
} \
} while (0)
-PyMODINIT_FUNC
-PyInit__io(void)
+static int
+iomodule_exec(PyObject *m)
{
- PyObject *m = PyModule_Create(&_PyIO_Module);
- _PyIO_State *state = NULL;
- if (m == NULL)
- return NULL;
- state = get_io_state(m);
- state->initialized = 0;
+ _PyIO_State *state = get_io_state(m);
/* DEFAULT_BUFFER_SIZE */
if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
- goto fail;
+ return -1;
/* UnsupportedOperation inherits from ValueError and OSError */
state->unsupported_operation = PyObject_CallFunction(
(PyObject *)&PyType_Type, "s(OO){}",
"UnsupportedOperation", PyExc_OSError, PyExc_ValueError);
if (state->unsupported_operation == NULL)
- goto fail;
+ return -1;
if (PyModule_AddObjectRef(m, "UnsupportedOperation",
state->unsupported_operation) < 0)
{
- goto fail;
+ return -1;
}
/* BlockingIOError, for compatibility */
if (PyModule_AddObjectRef(m, "BlockingIOError",
(PyObject *) PyExc_BlockingIOError) < 0) {
- goto fail;
- }
-
- // Add types
- for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
- PyTypeObject *type = static_types[i];
- if (PyModule_AddType(m, type) < 0) {
- goto fail;
- }
+ return -1;
}
// Base classes
- state->PyIOBase_Type = (PyTypeObject *)Py_NewRef(&PyIOBase_Type);
ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL);
ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL);
+ ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL);
// PyIOBase_Type subclasses
- state->PyRawIOBase_Type = (PyTypeObject *)Py_NewRef(&PyRawIOBase_Type);
- state->PyBufferedIOBase_Type = (PyTypeObject *)Py_NewRef(&PyBufferedIOBase_Type);
- state->PyTextIOBase_Type = (PyTypeObject *)Py_NewRef(&PyTextIOBase_Type);
+ ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec,
+ state->PyIOBase_Type);
+ ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec,
+ state->PyIOBase_Type);
+ ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec,
+ state->PyIOBase_Type);
// PyBufferedIOBase_Type(PyIOBase_Type) subclasses
ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type);
@@ -775,6 +699,7 @@ PyInit__io(void)
// PyRawIOBase_Type(PyIOBase_Type) subclasses
ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type);
+
#ifdef HAVE_WINDOWS_CONSOLE_IO
ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec,
state->PyRawIOBase_Type);
@@ -785,11 +710,30 @@ PyInit__io(void)
ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec,
state->PyTextIOBase_Type);
- state->initialized = 1;
+#undef ADD_TYPE
+ return 0;
+}
- return m;
+static struct PyModuleDef_Slot iomodule_slots[] = {
+ {Py_mod_exec, iomodule_exec},
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+ {0, NULL},
+};
- fail:
- Py_DECREF(m);
- return NULL;
+struct PyModuleDef _PyIO_Module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "io",
+ .m_doc = module_doc,
+ .m_size = sizeof(_PyIO_State),
+ .m_methods = module_methods,
+ .m_traverse = iomodule_traverse,
+ .m_clear = iomodule_clear,
+ .m_free = iomodule_free,
+ .m_slots = iomodule_slots,
+};
+
+PyMODINIT_FUNC
+PyInit__io(void)
+{
+ return PyModuleDef_Init(&_PyIO_Module);
}
diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h
index ae06fecc48..afd638a120 100644
--- a/Modules/_io/_iomodule.h
+++ b/Modules/_io/_iomodule.h
@@ -8,13 +8,8 @@
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "structmember.h"
-/* ABCs */
-extern PyTypeObject PyIOBase_Type;
-extern PyTypeObject PyRawIOBase_Type;
-extern PyTypeObject PyBufferedIOBase_Type;
-extern PyTypeObject PyTextIOBase_Type;
-
/* Type specs */
+extern PyType_Spec bufferediobase_spec;
extern PyType_Spec bufferedrandom_spec;
extern PyType_Spec bufferedreader_spec;
extern PyType_Spec bufferedrwpair_spec;
@@ -22,8 +17,11 @@ extern PyType_Spec bufferedwriter_spec;
extern PyType_Spec bytesio_spec;
extern PyType_Spec bytesiobuf_spec;
extern PyType_Spec fileio_spec;
+extern PyType_Spec iobase_spec;
extern PyType_Spec nldecoder_spec;
+extern PyType_Spec rawiobase_spec;
extern PyType_Spec stringio_spec;
+extern PyType_Spec textiobase_spec;
extern PyType_Spec textiowrapper_spec;
#ifdef HAVE_WINDOWS_CONSOLE_IO
@@ -168,9 +166,6 @@ struct _io_state {
#endif
};
-#define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod))
-#define IO_STATE() _PyIO_get_module_state()
-
static inline _PyIO_State *
get_io_state(PyObject *module)
{
@@ -195,7 +190,7 @@ find_io_state_by_def(PyTypeObject *type)
return get_io_state(mod);
}
-extern _PyIO_State *_PyIO_get_module_state(void);
+extern PyObject *_PyIOBase_cannot_pickle(PyObject *self, PyObject *args);
#ifdef HAVE_WINDOWS_CONSOLE_IO
extern char _PyIO_get_console_type(PyObject *);
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 00e228bca4..d5cc047bd8 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -16,14 +16,14 @@
/*[clinic input]
module _io
-class _io._BufferedIOBase "PyObject *" "&PyBufferedIOBase_Type"
-class _io._Buffered "buffered *" "&PyBufferedIOBase_Type"
+class _io._BufferedIOBase "PyObject *" "clinic_state()->PyBufferedIOBase_Type"
+class _io._Buffered "buffered *" "clinic_state()->PyBufferedIOBase_Type"
class _io.BufferedReader "buffered *" "clinic_state()->PyBufferedReader_Type"
class _io.BufferedWriter "buffered *" "clinic_state()->PyBufferedWriter_Type"
class _io.BufferedRWPair "rwpair *" "clinic_state()->PyBufferedRWPair_Type"
class _io.BufferedRandom "buffered *" "clinic_state()->PyBufferedRandom_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=abd685b9d94b9888]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3b3ef9cbbbad4590]*/
/*
* BufferedIOBase class, inherits from IOBase.
@@ -128,7 +128,7 @@ static PyObject *
_io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls)
/*[clinic end generated code: output=b87b135d67cd4448 input=0b61a7b4357c1ea7]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return bufferediobase_unsupported(state, "detach");
}
@@ -162,7 +162,7 @@ _io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls,
PyObject *args)
/*[clinic end generated code: output=4521b30940fd7b67 input=390205758adc8510]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return bufferediobase_unsupported(state, "read");
}
@@ -184,7 +184,7 @@ _io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls,
PyObject *args)
/*[clinic end generated code: output=636fd241c21e050a input=ef546a1238c5b41c]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return bufferediobase_unsupported(state, "read1");
}
@@ -209,7 +209,7 @@ _io__BufferedIOBase_write_impl(PyObject *self, PyTypeObject *cls,
PyObject *args)
/*[clinic end generated code: output=d51feea4bcac9892 input=f79b72c4dccb3dc2]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return bufferediobase_unsupported(state, "write");
}
@@ -394,6 +394,15 @@ _enter_buffered_busy(buffered *self)
(self->buffer_size * (size / self->buffer_size)))
+static int
+buffered_clear(buffered *self)
+{
+ self->ok = 0;
+ Py_CLEAR(self->raw);
+ Py_CLEAR(self->dict);
+ return 0;
+}
+
static void
buffered_dealloc(buffered *self)
{
@@ -405,7 +414,6 @@ buffered_dealloc(buffered *self)
self->ok = 0;
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
- Py_CLEAR(self->raw);
if (self->buffer) {
PyMem_Free(self->buffer);
self->buffer = NULL;
@@ -414,7 +422,7 @@ buffered_dealloc(buffered *self)
PyThread_free_lock(self->lock);
self->lock = NULL;
}
- Py_CLEAR(self->dict);
+ (void)buffered_clear(self);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
}
@@ -443,15 +451,6 @@ buffered_traverse(buffered *self, visitproc visit, void *arg)
return 0;
}
-static int
-buffered_clear(buffered *self)
-{
- self->ok = 0;
- Py_CLEAR(self->raw);
- Py_CLEAR(self->dict);
- return 0;
-}
-
/* Because this can call arbitrary code, it shouldn't be called when
the refcount is 0 (that is, not directly from tp_dealloc unless
the refcount has been temporarily re-incremented). */
@@ -2220,6 +2219,8 @@ bufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
Py_VISIT(self->dict);
+ Py_VISIT(self->reader);
+ Py_VISIT(self->writer);
return 0;
}
@@ -2239,9 +2240,7 @@ bufferedrwpair_dealloc(rwpair *self)
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
- Py_CLEAR(self->reader);
- Py_CLEAR(self->writer);
- Py_CLEAR(self->dict);
+ (void)bufferedrwpair_clear(self);
tp->tp_free((PyObject *) self);
Py_DECREF(tp);
}
@@ -2424,6 +2423,12 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw,
#include "clinic/bufferedio.c.h"
#undef clinic_state
+static int
+bufferediobase_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
static PyMethodDef bufferediobase_methods[] = {
_IO__BUFFEREDIOBASE_DETACH_METHODDEF
@@ -2435,57 +2440,19 @@ static PyMethodDef bufferediobase_methods[] = {
{NULL, NULL}
};
-PyTypeObject PyBufferedIOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_io._BufferedIOBase", /*tp_name*/
- 0, /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- bufferediobase_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- bufferediobase_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &PyIOBase_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
- 0, /* tp_is_gc */
- 0, /* tp_bases */
- 0, /* tp_mro */
- 0, /* tp_cache */
- 0, /* tp_subclasses */
- 0, /* tp_weaklist */
- 0, /* tp_del */
- 0, /* tp_version_tag */
- 0, /* tp_finalize */
+static PyType_Slot bufferediobase_slots[] = {
+ {Py_tp_doc, (void *)bufferediobase_doc},
+ {Py_tp_methods, bufferediobase_methods},
+ {Py_tp_traverse, bufferediobase_traverse},
+ {0, NULL},
};
+PyType_Spec bufferediobase_spec = {
+ .name = "_io._BufferedIOBase",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = bufferediobase_slots,
+};
static PyMethodDef bufferedreader_methods[] = {
/* BufferedIOMixin methods */
@@ -2508,6 +2475,9 @@ static PyMethodDef bufferedreader_methods[] = {
_IO__BUFFERED_TELL_METHODDEF
_IO__BUFFERED_TRUNCATE_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
+
+ {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS},
+ {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS},
{NULL, NULL}
};
@@ -2565,6 +2535,9 @@ static PyMethodDef bufferedwriter_methods[] = {
_IO__BUFFERED_SEEK_METHODDEF
_IO__BUFFERED_TELL_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
+
+ {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS},
+ {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS},
{NULL, NULL}
};
@@ -2680,6 +2653,9 @@ static PyMethodDef bufferedrandom_methods[] = {
_IO__BUFFERED_PEEK_METHODDEF
_IO_BUFFEREDWRITER_WRITE_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
+
+ {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS},
+ {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS},
{NULL, NULL}
};
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
index 3fddfc2ed0..8077305869 100644
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -979,6 +979,7 @@ bytesio_traverse(bytesio *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
Py_VISIT(self->dict);
+ Py_VISIT(self->buf);
return 0;
}
@@ -986,6 +987,7 @@ static int
bytesio_clear(bytesio *self)
{
Py_CLEAR(self->dict);
+ Py_CLEAR(self->buf);
return 0;
}
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 473f0a8a6b..30944fc56b 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -536,7 +536,7 @@ fileio_dealloc(fileio *self)
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
- Py_CLEAR(self->dict);
+ (void)fileio_clear(self);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
}
@@ -1166,6 +1166,8 @@ static PyMethodDef fileio_methods[] = {
_IO_FILEIO_FILENO_METHODDEF
_IO_FILEIO_ISATTY_METHODDEF
{"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
+ {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS},
+ {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
index 26f2a3155b..764c5fb332 100644
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -17,10 +17,10 @@
/*[clinic input]
module _io
-class _io._IOBase "PyObject *" "&PyIOBase_Type"
-class _io._RawIOBase "PyObject *" "&PyRawIOBase_Type"
+class _io._IOBase "PyObject *" "clinic_state()->PyIOBase_Type"
+class _io._RawIOBase "PyObject *" "clinic_state()->PyRawIOBase_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d29a4d076c2b211c]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9006b7802ab8ea85]*/
/*
* IOBase class, an abstract class
@@ -101,7 +101,7 @@ static PyObject *
_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, PyObject *args)
/*[clinic end generated code: output=1dd694ac9de260fa input=ebb5476eb22fc5d4]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return iobase_unsupported(state, "seek");
}
@@ -134,7 +134,7 @@ static PyObject *
_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *args)
/*[clinic end generated code: output=b7eed4649cbe22c1 input=ad90582a1d8b5cc9]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return iobase_unsupported(state, "truncate");
}
@@ -220,24 +220,32 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args)
static PyObject *
iobase_check_seekable(PyObject *self, PyObject *args)
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = find_io_state_by_def(Py_TYPE(self));
return _PyIOBase_check_seekable(state, self, args);
}
static PyObject *
iobase_check_readable(PyObject *self, PyObject *args)
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = find_io_state_by_def(Py_TYPE(self));
return _PyIOBase_check_readable(state, self, args);
}
static PyObject *
iobase_check_writable(PyObject *self, PyObject *args)
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = find_io_state_by_def(Py_TYPE(self));
return _PyIOBase_check_writable(state, self, args);
}
+PyObject *
+_PyIOBase_cannot_pickle(PyObject *self, PyObject *args)
+{
+ PyErr_Format(PyExc_TypeError,
+ "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self)));
+ return NULL;
+}
+
/* XXX: IOBase thinks it has to maintain its own internal state in
`__IOBase_closed` and call flush() by itself, but it is redundant with
whatever behaviour a non-trivial derived class will implement. */
@@ -351,6 +359,7 @@ _PyIOBase_finalize(PyObject *self)
static int
iobase_traverse(iobase *self, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(self));
Py_VISIT(self->dict);
return 0;
}
@@ -380,11 +389,13 @@ iobase_dealloc(iobase *self)
}
return;
}
+ PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
Py_CLEAR(self->dict);
- Py_TYPE(self)->tp_free((PyObject *) self);
+ tp->tp_free((PyObject *)self);
+ Py_DECREF(tp);
}
/* Inquiry methods */
@@ -523,7 +534,7 @@ static PyObject *
_io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls)
/*[clinic end generated code: output=7caaa32a6f4ada3d input=1927c8bea5c85099]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return iobase_unsupported(state, "fileno");
}
@@ -821,7 +832,9 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines)
Py_RETURN_NONE;
}
+#define clinic_state() (find_io_state_by_def(Py_TYPE(self)))
#include "clinic/iobase.c.h"
+#undef clinic_state
static PyMethodDef iobase_methods[] = {
_IO__IOBASE_SEEK_METHODDEF
@@ -858,59 +871,34 @@ static PyGetSetDef iobase_getset[] = {
{NULL}
};
+static struct PyMemberDef iobase_members[] = {
+ {"__weaklistoffset__", T_PYSSIZET, offsetof(iobase, weakreflist), READONLY},
+ {"__dictoffset__", T_PYSSIZET, offsetof(iobase, dict), READONLY},
+ {NULL},
+};
+
-PyTypeObject PyIOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_io._IOBase", /*tp_name*/
- sizeof(iobase), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)iobase_dealloc, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
- | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
- iobase_doc, /* tp_doc */
- (traverseproc)iobase_traverse, /* tp_traverse */
- (inquiry)iobase_clear, /* tp_clear */
- 0, /* tp_richcompare */
- offsetof(iobase, weakreflist), /* tp_weaklistoffset */
- iobase_iter, /* tp_iter */
- iobase_iternext, /* tp_iternext */
- iobase_methods, /* tp_methods */
- 0, /* tp_members */
- iobase_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- offsetof(iobase, dict), /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
- 0, /* tp_free */
- 0, /* tp_is_gc */
- 0, /* tp_bases */
- 0, /* tp_mro */
- 0, /* tp_cache */
- 0, /* tp_subclasses */
- 0, /* tp_weaklist */
- 0, /* tp_del */
- 0, /* tp_version_tag */
- iobase_finalize, /* tp_finalize */
+static PyType_Slot iobase_slots[] = {
+ {Py_tp_dealloc, iobase_dealloc},
+ {Py_tp_doc, (void *)iobase_doc},
+ {Py_tp_traverse, iobase_traverse},
+ {Py_tp_clear, iobase_clear},
+ {Py_tp_iter, iobase_iter},
+ {Py_tp_iternext, iobase_iternext},
+ {Py_tp_methods, iobase_methods},
+ {Py_tp_members, iobase_members},
+ {Py_tp_getset, iobase_getset},
+ {Py_tp_finalize, iobase_finalize},
+ {0, NULL},
};
+PyType_Spec iobase_spec = {
+ .name = "_io._IOBase",
+ .basicsize = sizeof(iobase),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = iobase_slots,
+};
/*
* RawIOBase class, Inherits from IOBase.
@@ -1045,6 +1033,13 @@ rawiobase_write(PyObject *self, PyObject *args)
return NULL;
}
+static int
+rawiobase_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
+
static PyMethodDef rawiobase_methods[] = {
_IO__RAWIOBASE_READ_METHODDEF
_IO__RAWIOBASE_READALL_METHODDEF
@@ -1053,53 +1048,16 @@ static PyMethodDef rawiobase_methods[] = {
{NULL, NULL}
};
-PyTypeObject PyRawIOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_io._RawIOBase", /*tp_name*/
- 0, /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- rawiobase_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- rawiobase_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &PyIOBase_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
- 0, /* tp_is_gc */
- 0, /* tp_bases */
- 0, /* tp_mro */
- 0, /* tp_cache */
- 0, /* tp_subclasses */
- 0, /* tp_weaklist */
- 0, /* tp_del */
- 0, /* tp_version_tag */
- 0, /* tp_finalize */
+static PyType_Slot rawiobase_slots[] = {
+ {Py_tp_doc, (void *)rawiobase_doc},
+ {Py_tp_methods, rawiobase_methods},
+ {Py_tp_traverse, rawiobase_traverse},
+ {0, NULL},
+};
+
+PyType_Spec rawiobase_spec = {
+ .name = "_io._RawIOBase",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = rawiobase_slots,
};
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
index 13d3b870b3..3eb25704b4 100644
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -583,6 +583,9 @@ static int
stringio_traverse(stringio *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
+ Py_VISIT(self->readnl);
+ Py_VISIT(self->writenl);
+ Py_VISIT(self->decoder);
Py_VISIT(self->dict);
return 0;
}
@@ -590,6 +593,9 @@ stringio_traverse(stringio *self, visitproc visit, void *arg)
static int
stringio_clear(stringio *self)
{
+ Py_CLEAR(self->readnl);
+ Py_CLEAR(self->writenl);
+ Py_CLEAR(self->decoder);
Py_CLEAR(self->dict);
return 0;
}
@@ -605,10 +611,7 @@ stringio_dealloc(stringio *self)
self->buf = NULL;
}
_PyUnicodeWriter_Dealloc(&self->writer);
- Py_CLEAR(self->readnl);
- Py_CLEAR(self->writenl);
- Py_CLEAR(self->decoder);
- Py_CLEAR(self->dict);
+ (void)stringio_clear(self);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 3cc292cc35..81dd3bed00 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -62,7 +62,7 @@ static PyObject *
_io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls)
/*[clinic end generated code: output=50915f40c609eaa4 input=987ca3640d0a3776]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return _unsupported(state, "detach");
}
@@ -82,7 +82,7 @@ static PyObject *
_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args)
/*[clinic end generated code: output=3adf28998831f461 input=cee1e84664a20de0]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return _unsupported(state, "read");
}
@@ -102,7 +102,7 @@ _io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls,
PyObject *args)
/*[clinic end generated code: output=3073a948d02319f3 input=58f801259f7ff3ef]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return _unsupported(state, "readline");
}
@@ -122,7 +122,7 @@ static PyObject *
_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args)
/*[clinic end generated code: output=5d985eb529472bc4 input=21b6961b5cba9496]*/
{
- _PyIO_State *state = IO_STATE();
+ _PyIO_State *state = get_io_state_by_cls(cls);
return _unsupported(state, "write");
}
@@ -164,6 +164,12 @@ textiobase_errors_get(PyObject *self, void *context)
Py_RETURN_NONE;
}
+static int
+textiobase_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
static PyMethodDef textiobase_methods[] = {
_IO__TEXTIOBASE_DETACH_METHODDEF
@@ -180,57 +186,20 @@ static PyGetSetDef textiobase_getset[] = {
{NULL}
};
-PyTypeObject PyTextIOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_io._TextIOBase", /*tp_name*/
- 0, /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- textiobase_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- textiobase_methods, /* tp_methods */
- 0, /* tp_members */
- textiobase_getset, /* tp_getset */
- &PyIOBase_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
- 0, /* tp_is_gc */
- 0, /* tp_bases */
- 0, /* tp_mro */
- 0, /* tp_cache */
- 0, /* tp_subclasses */
- 0, /* tp_weaklist */
- 0, /* tp_del */
- 0, /* tp_version_tag */
- 0, /* tp_finalize */
+static PyType_Slot textiobase_slots[] = {
+ {Py_tp_doc, (void *)textiobase_doc},
+ {Py_tp_methods, textiobase_methods},
+ {Py_tp_getset, textiobase_getset},
+ {Py_tp_traverse, textiobase_traverse},
+ {0, NULL},
};
+PyType_Spec textiobase_spec = {
+ .name = "_io._TextIOBase",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = textiobase_slots,
+};
/* IncrementalNewlineDecoder */
@@ -1456,7 +1425,7 @@ textiowrapper_dealloc(textio *self)
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
- textiowrapper_clear(self);
+ (void)textiowrapper_clear(self);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
}
@@ -3267,6 +3236,9 @@ static PyMethodDef textiowrapper_methods[] = {
_IO_TEXTIOWRAPPER_SEEK_METHODDEF
_IO_TEXTIOWRAPPER_TELL_METHODDEF
_IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF
+
+ {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS},
+ {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS},
{NULL, NULL}
};
diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c
index d65e247737..15f3053957 100644
--- a/Modules/_io/winconsoleio.c
+++ b/Modules/_io/winconsoleio.c
@@ -1096,7 +1096,7 @@ _io__WindowsConsoleIO_isatty_impl(winconsoleio *self)
Py_RETURN_TRUE;
}
-#define clinic_state() (IO_STATE())
+#define clinic_state() (find_io_state_by_def(Py_TYPE(self)))
#include "clinic/winconsoleio.c.h"
#undef clinic_state
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 61f87c5eba..c5dc0f44a3 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -29,9 +29,6 @@
#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
#include "opcode.h"
-extern PyStatus _PyIO_InitTypes(PyInterpreterState *interp);
-extern void _PyIO_FiniTypes(PyInterpreterState *interp);
-
#include <locale.h> // setlocale()
#include <stdlib.h> // getenv()
@@ -706,11 +703,6 @@ pycore_init_types(PyInterpreterState *interp)
return _PyStatus_ERR("failed to initialize an exception type");
}
- status = _PyIO_InitTypes(interp);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
status = _PyExc_InitGlobalObjects(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
@@ -1667,8 +1659,6 @@ flush_std_files(void)
static void
finalize_interp_types(PyInterpreterState *interp)
{
- _PyIO_FiniTypes(interp);
-
_PyUnicode_FiniTypes(interp);
_PySys_FiniTypes(interp);
_PyExc_Fini(interp);
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index 8afa92ef25..9863acdade 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -317,10 +317,6 @@ Python/instrumentation.c - _PyInstrumentation_MISSING -
##-----------------------
## static types
-Modules/_io/bufferedio.c - PyBufferedIOBase_Type -
-Modules/_io/iobase.c - PyIOBase_Type -
-Modules/_io/iobase.c - PyRawIOBase_Type -
-Modules/_io/textio.c - PyTextIOBase_Type -
Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type -
Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type -
Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type -