From 6d0a37b18f696268f64209efce28e6a21b7a2a28 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Feb 2023 22:48:03 +0100 Subject: [PATCH 01/54] Add tests --- Lib/test/test_io.py | 91 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index c5f2e5060a546d..45d5465b9dff99 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1042,6 +1042,95 @@ def close(self): support.gc_collect() self.assertIsNone(wr(), wr) +@support.cpython_only +class TestIOCTypes(unittest.TestCase): + def setUp(self): + _io = import_helper.import_module("_io") + self.types = ( + _io.BufferedRWPair, + _io.BufferedRandom, + _io.BufferedReader, + _io.BufferedWriter, + _io.BytesIO, + _io.FileIO, + _io.IncrementalNewlineDecoder, + _io.StringIO, + _io.TextIOWrapper, + _io._BufferedIOBase, + _io._BytesIOBuffer, + _io._IOBase, + _io._RawIOBase, + _io._TextIOBase, + ) + if sys.platform == "win32": + self.types.append(_io._WindowsConsoleIO) + self._io = _io + + def test_immutable_types(self): + for tp in self.types: + with self.subTest(tp=tp): + with self.assertRaisesRegex(TypeError, "immutable"): + tp.foo = "bar" + + def test_class_hierarchy(self): + def check_subs(types, base): + for tp in types: + with self.subTest(tp=tp, base=base): + self.assertTrue(issubclass(tp, base)) + + def recursive_check(d): + for k, v in d.items(): + if isinstance(v, dict): + recursive_check(v) + elif isinstance(v, set): + check_subs(v, k) + else: + self.fail("corrupt test dataset") + + _io = self._io + hierarchy = { + _io._IOBase: { + _io._BufferedIOBase: { + _io.BufferedRWPair, + _io.BufferedRandom, + _io.BufferedReader, + _io.BufferedWriter, + _io.BytesIO, + }, + _io._RawIOBase: { + _io.FileIO, + }, + _io._TextIOBase: { + _io.StringIO, + _io.TextIOWrapper, + }, + }, + } + if sys.platform == "win32": + hierarchy[_io._IOBase][_io._RawIOBase].add(_io._WindowsConsoleIO) + + recursive_check(hierarchy) + + def test_subclassing(self): + _io = self._io + dataset = {k: True for k in self.types} + dataset[_io._BytesIOBuffer] = False + + for tp, is_basetype in dataset.items(): + with self.subTest(tp=tp, is_basetype=is_basetype): + name = f"{tp.__name__}_subclass" + bases = (tp,) + if is_basetype: + _ = type(name, bases, {}) + else: + msg = "not an acceptable base type" + with self.assertRaisesRegex(TypeError, msg): + _ = type(name, bases, {}) + + def test_disallow_instantiation(self): + _io = self._io + support.check_disallow_instantiation(self, _io._BytesIOBuffer) + class PyIOTest(IOTest): pass @@ -4671,7 +4760,7 @@ def load_tests(loader, tests, pattern): CIncrementalNewlineDecoderTest, PyIncrementalNewlineDecoderTest, CTextIOWrapperTest, PyTextIOWrapperTest, CMiscIOTest, PyMiscIOTest, - CSignalsTest, PySignalsTest, + CSignalsTest, PySignalsTest, TestIOCTypes, ) # Put the namespaces of the IO module we are testing and some useful mock From bd19a20f18e048b368b6077de6964afe93564795 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 11 Feb 2023 09:42:23 +0100 Subject: [PATCH 02/54] StringIO type --- Modules/_io/_iomodule.c | 17 ++++- Modules/_io/_iomodule.h | 9 ++- Modules/_io/stringio.c | 83 ++++++++++----------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 61 insertions(+), 49 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 811b1d221a0122..4769b464432ece 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -612,7 +612,9 @@ iomodule_free(PyObject *mod) { * Module definition */ +#define clinic_state() (IO_STATE()) #include "clinic/_iomodule.c.h" +#undef clinic_state static PyMethodDef module_methods[] = { _IO_OPEN_METHODDEF @@ -659,7 +661,6 @@ static PyTypeObject* static_types[] = { #endif // PyTextIOBase_Type(PyIOBase_Type) subclasses - &PyStringIO_Type, &PyTextIOWrapper_Type, }; @@ -673,6 +674,17 @@ _PyIO_Fini(void) } } +#define ADD_TYPE(module, type, spec, base) \ +do { \ + type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ + (PyObject *)base); \ + if (type == NULL) { \ + goto fail; \ + } \ + if (PyModule_AddType(module, type) < 0) { \ + goto fail; \ + } \ +} while (0) PyMODINIT_FUNC PyInit__io(void) @@ -707,7 +719,6 @@ PyInit__io(void) // Set type base classes PyFileIO_Type.tp_base = &PyRawIOBase_Type; PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type; - PyStringIO_Type.tp_base = &PyTextIOBase_Type; #ifdef MS_WINDOWS PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; #endif @@ -725,6 +736,8 @@ PyInit__io(void) } } + ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, &PyTextIOBase_Type); + state->initialized = 1; return m; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 7617cb8fb70e43..517ba6bbb95ef2 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -4,6 +4,8 @@ #include "exports.h" +#include "structmember.h" + /* ABCs */ extern PyTypeObject PyIOBase_Type; extern PyTypeObject PyRawIOBase_Type; @@ -13,7 +15,6 @@ extern PyTypeObject PyTextIOBase_Type; /* Concrete classes */ extern PyTypeObject PyFileIO_Type; extern PyTypeObject PyBytesIO_Type; -extern PyTypeObject PyStringIO_Type; extern PyTypeObject PyBufferedReader_Type; extern PyTypeObject PyBufferedWriter_Type; extern PyTypeObject PyBufferedRWPair_Type; @@ -21,6 +22,9 @@ extern PyTypeObject PyBufferedRandom_Type; extern PyTypeObject PyTextIOWrapper_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; +/* Type specs */ +extern PyType_Spec stringio_spec; + #ifdef MS_WINDOWS extern PyTypeObject PyWindowsConsoleIO_Type; #endif /* MS_WINDOWS */ @@ -140,6 +144,9 @@ typedef struct { PyObject *locale_module; PyObject *unsupported_operation; + + /* Types */ + PyTypeObject *PyStringIO_Type; } _PyIO_State; #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index ae6c3125a2d9da..12ae5a09ca70a2 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -13,9 +13,9 @@ /*[clinic input] module _io -class _io.StringIO "stringio *" "&PyStringIO_Type" +class _io.StringIO "stringio *" "clinic_state()->PyStringIO_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c17bc0f42165cd7d]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2693eada0658d470]*/ typedef struct { PyObject_HEAD @@ -401,7 +401,8 @@ stringio_iternext(stringio *self) CHECK_CLOSED(self); ENSURE_REALIZED(self); - if (Py_IS_TYPE(self, &PyStringIO_Type)) { + _PyIO_State *state = IO_STATE(); + if (Py_IS_TYPE(self, state->PyStringIO_Type)) { /* Skip method call overhead for speed */ line = _stringio_readline(self, -1); } @@ -581,6 +582,7 @@ _io_StringIO_close_impl(stringio *self) static int stringio_traverse(stringio *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } @@ -595,6 +597,7 @@ stringio_clear(stringio *self) static void stringio_dealloc(stringio *self) { + PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); self->ok = 0; if (self->buf) { @@ -606,9 +609,11 @@ stringio_dealloc(stringio *self) Py_CLEAR(self->writenl); Py_CLEAR(self->decoder); Py_CLEAR(self->dict); - if (self->weakreflist != NULL) + if (self->weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) self); - Py_TYPE(self)->tp_free(self); + } + tp->tp_free(self); + Py_DECREF(tp); } static PyObject * @@ -963,7 +968,9 @@ stringio_newlines(stringio *self, void *context) return PyObject_GetAttr(self->decoder, &_Py_ID(newlines)); } +#define clinic_state() (IO_STATE()) #include "clinic/stringio.c.h" +#undef clinic_state static struct PyMethodDef stringio_methods[] = { _IO_STRINGIO_CLOSE_METHODDEF @@ -997,44 +1004,30 @@ static PyGetSetDef stringio_getset[] = { {NULL} }; -PyTypeObject PyStringIO_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.StringIO", /*tp_name*/ - sizeof(stringio), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)stringio_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*/ - _io_StringIO___init____doc__, /*tp_doc*/ - (traverseproc)stringio_traverse, /*tp_traverse*/ - (inquiry)stringio_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - offsetof(stringio, weakreflist), /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - (iternextfunc)stringio_iternext, /*tp_iternext*/ - stringio_methods, /*tp_methods*/ - 0, /*tp_members*/ - stringio_getset, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - offsetof(stringio, dict), /*tp_dictoffset*/ - _io_StringIO___init__, /*tp_init*/ - 0, /*tp_alloc*/ - stringio_new, /*tp_new*/ +static struct PyMemberDef stringio_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(stringio, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(stringio, dict), READONLY}, + {NULL}, +}; + +static PyType_Slot stringio_slots[] = { + {Py_tp_dealloc, stringio_dealloc}, + {Py_tp_doc, (void *)_io_StringIO___init____doc__}, + {Py_tp_traverse, stringio_traverse}, + {Py_tp_clear, stringio_clear}, + {Py_tp_iternext, stringio_iternext}, + {Py_tp_methods, stringio_methods}, + {Py_tp_members, stringio_members}, + {Py_tp_getset, stringio_getset}, + {Py_tp_init, _io_StringIO___init__}, + {Py_tp_new, stringio_new}, + {0, NULL}, +}; + +PyType_Spec stringio_spec = { + .name = "_io.StringIO", + .basicsize = sizeof(stringio), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = stringio_slots, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 6011b1604508af..9ea82ad8b656bc 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -326,7 +326,6 @@ Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/fileio.c - PyFileIO_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - -Modules/_io/stringio.c - PyStringIO_Type - Modules/_io/textio.c - PyIncrementalNewlineDecoder_Type - Modules/_io/textio.c - PyTextIOBase_Type - Modules/_io/textio.c - PyTextIOWrapper_Type - From 9af73fea92b88c6dc95fee7df45d41405850e70e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 11 Feb 2023 14:52:44 +0100 Subject: [PATCH 03/54] PyTextIOWrapper type --- Modules/_io/_iomodule.c | 10 +-- Modules/_io/_iomodule.h | 3 +- Modules/_io/textio.c | 91 ++++++++------------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 43 insertions(+), 62 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 4769b464432ece..9f89b0c68a2834 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -417,7 +417,8 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, } /* wraps into a TextIOWrapper */ - wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type, + _PyIO_State *state = IO_STATE(); + wrapper = PyObject_CallFunction((PyObject *)state->PyTextIOWrapper_Type, "OsssO", buffer, encoding, errors, newline, @@ -659,9 +660,6 @@ static PyTypeObject* static_types[] = { #ifdef MS_WINDOWS &PyWindowsConsoleIO_Type, #endif - - // PyTextIOBase_Type(PyIOBase_Type) subclasses - &PyTextIOWrapper_Type, }; @@ -726,7 +724,6 @@ PyInit__io(void) PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type; PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type; PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type; - PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type; // Add types for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { @@ -736,7 +733,10 @@ PyInit__io(void) } } + // PyTextIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, &PyTextIOBase_Type); + ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, + &PyTextIOBase_Type); state->initialized = 1; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 517ba6bbb95ef2..d793bfd94e5f1a 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -19,11 +19,11 @@ extern PyTypeObject PyBufferedReader_Type; extern PyTypeObject PyBufferedWriter_Type; extern PyTypeObject PyBufferedRWPair_Type; extern PyTypeObject PyBufferedRandom_Type; -extern PyTypeObject PyTextIOWrapper_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; /* Type specs */ extern PyType_Spec stringio_spec; +extern PyType_Spec textiowrapper_spec; #ifdef MS_WINDOWS extern PyTypeObject PyWindowsConsoleIO_Type; @@ -147,6 +147,7 @@ typedef struct { /* Types */ PyTypeObject *PyStringIO_Type; + PyTypeObject *PyTextIOWrapper_Type; } _PyIO_State; #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index ea2ea32c336954..0dbdcab5ac2995 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -19,9 +19,9 @@ /*[clinic input] module _io class _io.IncrementalNewlineDecoder "nldecoder_object *" "&PyIncrementalNewlineDecoder_Type" -class _io.TextIOWrapper "textio *" "&TextIOWrapper_Type" +class _io.TextIOWrapper "textio *" "clinic_state()->TextIOWrapper_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ed072384f8aada2c]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d3f032e90f74c8f2]*/ /* TextIOBase */ @@ -682,6 +682,8 @@ typedef struct PyObject *weakreflist; PyObject *dict; + + _PyIO_State *state; } textio; static void @@ -1211,6 +1213,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; } + self->state = IO_STATE(); self->ok = 1; return 0; @@ -1387,6 +1390,7 @@ textiowrapper_clear(textio *self) static void textiowrapper_dealloc(textio *self) { + PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; @@ -1395,12 +1399,14 @@ textiowrapper_dealloc(textio *self) if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); textiowrapper_clear(self); - Py_TYPE(self)->tp_free((PyObject *)self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static int textiowrapper_traverse(textio *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->buffer); Py_VISIT(self->encoding); Py_VISIT(self->encoder); @@ -1424,7 +1430,7 @@ textiowrapper_closed_get(textio *self, void *context); do { \ int r; \ PyObject *_res; \ - if (Py_IS_TYPE(self, &PyTextIOWrapper_Type)) { \ + if (Py_IS_TYPE(self, self->state->PyTextIOWrapper_Type)) { \ if (self->raw != NULL) \ r = _PyFileIO_closed(self->raw); \ else { \ @@ -3053,7 +3059,8 @@ textiowrapper_iternext(textio *self) CHECK_ATTACHED(self); self->telling = 0; - if (Py_IS_TYPE(self, &PyTextIOWrapper_Type)) { + _PyIO_State *state = IO_STATE(); + if (Py_IS_TYPE(self, state->PyTextIOWrapper_Type)) { /* Skip method call overhead for speed */ line = _textiowrapper_readline(self, -1); } @@ -3145,7 +3152,9 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) return 0; } +#define clinic_state() (IO_STATE()) #include "clinic/textio.c.h" +#undef clinic_state static PyMethodDef incrementalnewlinedecoder_methods[] = { _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF @@ -3229,6 +3238,8 @@ static PyMemberDef textiowrapper_members[] = { {"line_buffering", T_BOOL, offsetof(textio, line_buffering), READONLY}, {"write_through", T_BOOL, offsetof(textio, write_through), READONLY}, {"_finalizing", T_BOOL, offsetof(textio, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(textio, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(textio, dict), READONLY}, {NULL} }; @@ -3244,54 +3255,24 @@ static PyGetSetDef textiowrapper_getset[] = { {NULL} }; -PyTypeObject PyTextIOWrapper_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.TextIOWrapper", /*tp_name*/ - sizeof(textio), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)textiowrapper_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tps_etattr*/ - 0, /*tp_as_async*/ - (reprfunc)textiowrapper_repr,/*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*/ - _io_TextIOWrapper___init____doc__, /* tp_doc */ - (traverseproc)textiowrapper_traverse, /* tp_traverse */ - (inquiry)textiowrapper_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(textio, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - (iternextfunc)textiowrapper_iternext, /* tp_iternext */ - textiowrapper_methods, /* tp_methods */ - textiowrapper_members, /* tp_members */ - textiowrapper_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(textio, dict), /*tp_dictoffset*/ - _io_TextIOWrapper___init__, /* 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 */ - 0, /* tp_finalize */ +PyType_Slot textiowrapper_slots[] = { + {Py_tp_dealloc, textiowrapper_dealloc}, + {Py_tp_repr, textiowrapper_repr}, + {Py_tp_doc, (void *)_io_TextIOWrapper___init____doc__}, + {Py_tp_traverse, textiowrapper_traverse}, + {Py_tp_clear, textiowrapper_clear}, + {Py_tp_iternext, textiowrapper_iternext}, + {Py_tp_methods, textiowrapper_methods}, + {Py_tp_members, textiowrapper_members}, + {Py_tp_getset, textiowrapper_getset}, + {Py_tp_init, _io_TextIOWrapper___init__}, + {0, NULL}, +}; + +PyType_Spec textiowrapper_spec = { + .name = "_io.TextIOWrapper", + .basicsize = sizeof(textio), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = textiowrapper_slots, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 9ea82ad8b656bc..208a9383cd3706 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -328,7 +328,6 @@ Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_io/textio.c - PyIncrementalNewlineDecoder_Type - Modules/_io/textio.c - PyTextIOBase_Type - -Modules/_io/textio.c - PyTextIOWrapper_Type - Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - From 4bd73bdd2753b40122ff09ff67476c03d785a1cd Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 11 Feb 2023 22:56:38 +0100 Subject: [PATCH 04/54] Move get_io_state() to main header --- Modules/_io/_iomodule.c | 9 --------- Modules/_io/_iomodule.h | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 9f89b0c68a2834..1b97f501423845 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -10,7 +10,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "_iomodule.h" -#include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pystate.h" // _PyInterpreterState_GET() #ifdef HAVE_SYS_TYPES_H @@ -559,14 +558,6 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err) return result; } -static inline _PyIO_State* -get_io_state(PyObject *module) -{ - void *state = _PyModule_GetState(module); - assert(state != NULL); - return (_PyIO_State *)state; -} - _PyIO_State * _PyIO_get_module_state(void) { diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index d793bfd94e5f1a..194a53848bd7d0 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -4,6 +4,7 @@ #include "exports.h" +#include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" /* ABCs */ @@ -153,6 +154,14 @@ typedef struct { #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) +{ + void *state = _PyModule_GetState(module); + assert(state != NULL); + return (_PyIO_State *)state; +} + extern _PyIO_State *_PyIO_get_module_state(void); #ifdef MS_WINDOWS From 8d96a7aabd29f2ef8b643898ff5a969e941d6d67 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 11 Feb 2023 22:59:33 +0100 Subject: [PATCH 05/54] PyFileIO type --- Modules/_io/_iomodule.c | 8 +- Modules/_io/_iomodule.h | 3 +- Modules/_io/bufferedio.c | 9 ++- Modules/_io/fileio.c | 86 +++++++-------------- Modules/_io/textio.c | 5 +- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 6 files changed, 46 insertions(+), 66 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1b97f501423845..1811f391c58d12 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -315,7 +315,8 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, /* Create the Raw file stream */ { - PyObject *RawIO_class = (PyObject *)&PyFileIO_Type; + _PyIO_State *state = get_io_state(module); + PyObject *RawIO_class = (PyObject *)state->PyFileIO_Type; #ifdef MS_WINDOWS const PyConfig *config = _Py_GetConfig(); if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') { @@ -646,7 +647,6 @@ static PyTypeObject* static_types[] = { &PyBufferedRandom_Type, // PyRawIOBase_Type(PyIOBase_Type) subclasses - &PyFileIO_Type, &_PyBytesIOBuffer_Type, #ifdef MS_WINDOWS &PyWindowsConsoleIO_Type, @@ -706,7 +706,6 @@ PyInit__io(void) } // Set type base classes - PyFileIO_Type.tp_base = &PyRawIOBase_Type; PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type; #ifdef MS_WINDOWS PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; @@ -724,6 +723,9 @@ PyInit__io(void) } } + // PyRawIOBase_Type(PyIOBase_Type) subclasses + ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); + // PyTextIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, &PyTextIOBase_Type); ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 194a53848bd7d0..993280b6916eb5 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -14,7 +14,6 @@ extern PyTypeObject PyBufferedIOBase_Type; extern PyTypeObject PyTextIOBase_Type; /* Concrete classes */ -extern PyTypeObject PyFileIO_Type; extern PyTypeObject PyBytesIO_Type; extern PyTypeObject PyBufferedReader_Type; extern PyTypeObject PyBufferedWriter_Type; @@ -23,6 +22,7 @@ extern PyTypeObject PyBufferedRandom_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; /* Type specs */ +extern PyType_Spec fileio_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiowrapper_spec; @@ -147,6 +147,7 @@ typedef struct { PyObject *unsupported_operation; /* Types */ + PyTypeObject *PyFileIO_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOWrapper_Type; } _PyIO_State; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index ba8969f0bcd100..692e21c55e1861 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1428,8 +1428,9 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, return -1; _bufferedreader_reset_buf(self); + _PyIO_State *state = IO_STATE(); self->fast_closed_checks = (Py_IS_TYPE(self, &PyBufferedReader_Type) && - Py_IS_TYPE(raw, &PyFileIO_Type)); + Py_IS_TYPE(raw, state->PyFileIO_Type)); self->ok = 1; return 0; @@ -1783,8 +1784,9 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; + _PyIO_State *state = IO_STATE(); self->fast_closed_checks = (Py_IS_TYPE(self, &PyBufferedWriter_Type) && - Py_IS_TYPE(raw, &PyFileIO_Type)); + Py_IS_TYPE(raw, state->PyFileIO_Type)); self->ok = 1; return 0; @@ -2295,8 +2297,9 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; + _PyIO_State *state = IO_STATE(); self->fast_closed_checks = (Py_IS_TYPE(self, &PyBufferedRandom_Type) && - Py_IS_TYPE(raw, &PyFileIO_Type)); + Py_IS_TYPE(raw, state->PyFileIO_Type)); self->ok = 1; return 0; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index d1a183cedac53a..36e3b30de97d07 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -51,7 +51,7 @@ /*[clinic input] module _io -class _io.FileIO "fileio *" "&PyFileIO_Type" +class _io.FileIO "fileio *" "clinic_state()->PyFileIO_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/ @@ -70,9 +70,7 @@ typedef struct { PyObject *dict; } fileio; -PyTypeObject PyFileIO_Type; - -#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type)) +#define PyFileIO_Check(state, op) (PyObject_TypeCheck((op), state->PyFileIO_Type)) /* Forward declarations */ static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error); @@ -242,7 +240,8 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int fstat_result; int async_err = 0; - assert(PyFileIO_Check(self)); + _PyIO_State *state = IO_STATE(); + assert(PyFileIO_Check(state, self)); if (self->fd >= 0) { if (self->closefd) { /* Have to close the existing file first. */ @@ -503,6 +502,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, static int fileio_traverse(fileio *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } @@ -517,6 +517,7 @@ fileio_clear(fileio *self) static void fileio_dealloc(fileio *self) { + PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; @@ -524,7 +525,8 @@ fileio_dealloc(fileio *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); } static PyObject * @@ -1177,57 +1179,29 @@ static PyGetSetDef fileio_getsetlist[] = { static PyMemberDef fileio_members[] = { {"_blksize", T_UINT, offsetof(fileio, blksize), 0}, {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(fileio, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(fileio, dict), READONLY}, {NULL} }; -PyTypeObject PyFileIO_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.FileIO", - sizeof(fileio), - 0, - (destructor)fileio_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)fileio_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - _io_FileIO___init____doc__, /* tp_doc */ - (traverseproc)fileio_traverse, /* tp_traverse */ - (inquiry)fileio_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(fileio, weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - fileio_methods, /* tp_methods */ - fileio_members, /* tp_members */ - fileio_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(fileio, dict), /* tp_dictoffset */ - _io_FileIO___init__, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - fileio_new, /* tp_new */ - PyObject_GC_Del, /* 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 fileio_slots[] = { + {Py_tp_dealloc, fileio_dealloc}, + {Py_tp_repr, fileio_repr}, + {Py_tp_doc, (void *)_io_FileIO___init____doc__}, + {Py_tp_traverse, fileio_traverse}, + {Py_tp_clear, fileio_clear}, + {Py_tp_methods, fileio_methods}, + {Py_tp_members, fileio_members}, + {Py_tp_getset, fileio_getsetlist}, + {Py_tp_init, _io_FileIO___init__}, + {Py_tp_new, fileio_new}, + {0, NULL}, +}; + +PyType_Spec fileio_spec = { + .name = "_io.FileIO", + .basicsize = sizeof(fileio), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = fileio_slots, }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 0dbdcab5ac2995..7080ba935d9cc0 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1177,6 +1177,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, /* Finished sorting out the codec details */ Py_CLEAR(codec_info); + _PyIO_State *state = IO_STATE(); if (Py_IS_TYPE(buffer, &PyBufferedReader_Type) || Py_IS_TYPE(buffer, &PyBufferedWriter_Type) || Py_IS_TYPE(buffer, &PyBufferedRandom_Type)) @@ -1185,7 +1186,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; /* Cache the raw FileIO object to speed up 'closed' checks */ if (raw != NULL) { - if (Py_IS_TYPE(raw, &PyFileIO_Type)) + if (Py_IS_TYPE(raw, state->PyFileIO_Type)) self->raw = raw; else Py_DECREF(raw); @@ -1213,7 +1214,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; } - self->state = IO_STATE(); + self->state = state; self->ok = 1; return 0; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 208a9383cd3706..a7582e6ee89b66 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -323,7 +323,6 @@ Modules/_io/bufferedio.c - PyBufferedReader_Type - Modules/_io/bufferedio.c - PyBufferedWriter_Type - Modules/_io/bytesio.c - PyBytesIO_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - -Modules/_io/fileio.c - PyFileIO_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_io/textio.c - PyIncrementalNewlineDecoder_Type - From 97f382f9070cc6b0d6f67bbc8ed67c00432e0797 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Feb 2023 13:10:18 +0100 Subject: [PATCH 06/54] Buffered* types --- Modules/_io/_iomodule.c | 35 +- Modules/_io/_iomodule.h | 12 +- Modules/_io/bufferedio.c | 335 +++++++------------- Modules/_io/clinic/bufferedio.c.h | 4 +- Modules/_io/fileio.c | 2 +- Modules/_io/textio.c | 6 +- Tools/c-analyzer/cpython/globals-to-fix.tsv | 4 - 7 files changed, 153 insertions(+), 245 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1811f391c58d12..e1ccb4d34c140a 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -386,16 +386,20 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, return result; } + _PyIO_State *state = IO_STATE(); /* wraps into a buffered file */ { PyObject *Buffered_class; - if (updating) - Buffered_class = (PyObject *)&PyBufferedRandom_Type; - else if (creating || writing || appending) - Buffered_class = (PyObject *)&PyBufferedWriter_Type; - else if (reading) - Buffered_class = (PyObject *)&PyBufferedReader_Type; + if (updating) { + Buffered_class = (PyObject *)state->PyBufferedRandom_Type; + } + else if (creating || writing || appending) { + Buffered_class = (PyObject *)state->PyBufferedWriter_Type; + } + else if (reading) { + Buffered_class = (PyObject *)state->PyBufferedReader_Type; + } else { PyErr_Format(PyExc_ValueError, "unknown mode: '%s'", mode); @@ -417,7 +421,6 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, } /* wraps into a TextIOWrapper */ - _PyIO_State *state = IO_STATE(); wrapper = PyObject_CallFunction((PyObject *)state->PyTextIOWrapper_Type, "OsssO", buffer, @@ -641,10 +644,6 @@ static PyTypeObject* static_types[] = { // PyBufferedIOBase_Type(PyIOBase_Type) subclasses &PyBytesIO_Type, - &PyBufferedReader_Type, - &PyBufferedWriter_Type, - &PyBufferedRWPair_Type, - &PyBufferedRandom_Type, // PyRawIOBase_Type(PyIOBase_Type) subclasses &_PyBytesIOBuffer_Type, @@ -710,10 +709,6 @@ PyInit__io(void) #ifdef MS_WINDOWS PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; #endif - PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type; - PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type; - PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type; - PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type; // Add types for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { @@ -723,6 +718,16 @@ PyInit__io(void) } } + // PyBufferedIOBase_Type(PyIOBase_Type) subclasses + ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, + &PyBufferedIOBase_Type); + ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec, + &PyBufferedIOBase_Type); + ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec, + &PyBufferedIOBase_Type); + ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, + &PyBufferedIOBase_Type); + // PyRawIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 993280b6916eb5..67a88a6969e103 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -15,13 +15,13 @@ extern PyTypeObject PyTextIOBase_Type; /* Concrete classes */ extern PyTypeObject PyBytesIO_Type; -extern PyTypeObject PyBufferedReader_Type; -extern PyTypeObject PyBufferedWriter_Type; -extern PyTypeObject PyBufferedRWPair_Type; -extern PyTypeObject PyBufferedRandom_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; /* Type specs */ +extern PyType_Spec bufferedrandom_spec; +extern PyType_Spec bufferedreader_spec; +extern PyType_Spec bufferedrwpair_spec; +extern PyType_Spec bufferedwriter_spec; extern PyType_Spec fileio_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiowrapper_spec; @@ -147,6 +147,10 @@ typedef struct { PyObject *unsupported_operation; /* Types */ + PyTypeObject *PyBufferedRWPair_Type; + PyTypeObject *PyBufferedRandom_Type; + PyTypeObject *PyBufferedReader_Type; + PyTypeObject *PyBufferedWriter_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOWrapper_Type; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 692e21c55e1861..ad9c1dfa0a0684 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -18,12 +18,12 @@ module _io class _io._BufferedIOBase "PyObject *" "&PyBufferedIOBase_Type" class _io._Buffered "buffered *" "&PyBufferedIOBase_Type" -class _io.BufferedReader "buffered *" "&PyBufferedReader_Type" -class _io.BufferedWriter "buffered *" "&PyBufferedWriter_Type" -class _io.BufferedRWPair "rwpair *" "&PyBufferedRWPair_Type" -class _io.BufferedRandom "buffered *" "&PyBufferedRandom_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=59460b9c5639984d]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=abd685b9d94b9888]*/ /* * BufferedIOBase class, inherits from IOBase. @@ -366,6 +366,7 @@ _enter_buffered_busy(buffered *self) static void buffered_dealloc(buffered *self) { + PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; @@ -383,7 +384,8 @@ buffered_dealloc(buffered *self) self->lock = NULL; } Py_CLEAR(self->dict); - Py_TYPE(self)->tp_free((PyObject *)self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -399,6 +401,7 @@ buffered_sizeof(buffered *self, PyObject *Py_UNUSED(ignored)) static int buffered_traverse(buffered *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->raw); Py_VISIT(self->dict); return 0; @@ -1328,9 +1331,11 @@ buffered_iternext(buffered *self) CHECK_INITIALIZED(self); + _PyIO_State *state = IO_STATE(); tp = Py_TYPE(self); - if (tp == &PyBufferedReader_Type || - tp == &PyBufferedRandom_Type) { + if (Py_IS_TYPE(tp, state->PyBufferedReader_Type) || + Py_IS_TYPE(tp, state->PyBufferedRandom_Type)) + { /* Skip method call overhead for speed */ line = _buffered_readline(self, -1); } @@ -1429,8 +1434,10 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, _bufferedreader_reset_buf(self); _PyIO_State *state = IO_STATE(); - self->fast_closed_checks = (Py_IS_TYPE(self, &PyBufferedReader_Type) && - Py_IS_TYPE(raw, state->PyFileIO_Type)); + self->fast_closed_checks = ( + Py_IS_TYPE(self, state->PyBufferedReader_Type) && + Py_IS_TYPE(raw, state->PyFileIO_Type) + ); self->ok = 1; return 0; @@ -1785,8 +1792,10 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, self->pos = 0; _PyIO_State *state = IO_STATE(); - self->fast_closed_checks = (Py_IS_TYPE(self, &PyBufferedWriter_Type) && - Py_IS_TYPE(raw, state->PyFileIO_Type)); + self->fast_closed_checks = ( + Py_IS_TYPE(self, state->PyBufferedWriter_Type) && + Py_IS_TYPE(raw, state->PyFileIO_Type) + ); self->ok = 1; return 0; @@ -2092,13 +2101,16 @@ _io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, if (_PyIOBase_check_writable(writer, Py_True) == NULL) return -1; + _PyIO_State *state = IO_STATE(); self->reader = (buffered *) PyObject_CallFunction( - (PyObject *) &PyBufferedReader_Type, "On", reader, buffer_size); + (PyObject *)state->PyBufferedReader_Type, + "On", reader, buffer_size); if (self->reader == NULL) return -1; self->writer = (buffered *) PyObject_CallFunction( - (PyObject *) &PyBufferedWriter_Type, "On", writer, buffer_size); + (PyObject *)state->PyBufferedWriter_Type, + "On", writer, buffer_size); if (self->writer == NULL) { Py_CLEAR(self->reader); return -1; @@ -2126,13 +2138,15 @@ bufferedrwpair_clear(rwpair *self) static void bufferedrwpair_dealloc(rwpair *self) { + PyTypeObject *tp = Py_TYPE(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); - Py_TYPE(self)->tp_free((PyObject *) self); + tp->tp_free((PyObject *) self); + Py_DECREF(tp); } static PyObject * @@ -2298,14 +2312,16 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, self->pos = 0; _PyIO_State *state = IO_STATE(); - self->fast_closed_checks = (Py_IS_TYPE(self, &PyBufferedRandom_Type) && + self->fast_closed_checks = (Py_IS_TYPE(self, state->PyBufferedRandom_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type)); self->ok = 1; return 0; } +#define clinic_state() (IO_STATE()) #include "clinic/bufferedio.c.h" +#undef clinic_state static PyMethodDef bufferediobase_methods[] = { @@ -2397,6 +2413,8 @@ static PyMethodDef bufferedreader_methods[] = { static PyMemberDef bufferedreader_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(buffered, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(buffered, dict), READONLY}, {NULL} }; @@ -2408,58 +2426,27 @@ static PyGetSetDef bufferedreader_getset[] = { }; -PyTypeObject PyBufferedReader_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BufferedReader", /*tp_name*/ - sizeof(buffered), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)buffered_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - (reprfunc)buffered_repr, /*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*/ - _io_BufferedReader___init____doc__, /* tp_doc */ - (traverseproc)buffered_traverse, /* tp_traverse */ - (inquiry)buffered_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - (iternextfunc)buffered_iternext, /* tp_iternext */ - bufferedreader_methods, /* tp_methods */ - bufferedreader_members, /* tp_members */ - bufferedreader_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(buffered, dict), /* tp_dictoffset */ - _io_BufferedReader___init__, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot bufferedreader_slots[] = { + {Py_tp_dealloc, buffered_dealloc}, + {Py_tp_repr, buffered_repr}, + {Py_tp_doc, (void *)_io_BufferedReader___init____doc__}, + {Py_tp_traverse, buffered_traverse}, + {Py_tp_clear, buffered_clear}, + {Py_tp_iternext, buffered_iternext}, + {Py_tp_methods, bufferedreader_methods}, + {Py_tp_members, bufferedreader_members}, + {Py_tp_getset, bufferedreader_getset}, + {Py_tp_init, _io_BufferedReader___init__}, + {0, NULL}, }; +PyType_Spec bufferedreader_spec = { + .name = "_io.BufferedReader", + .basicsize = sizeof(buffered), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = bufferedreader_slots, +}; static PyMethodDef bufferedwriter_methods[] = { /* BufferedIOMixin methods */ @@ -2483,6 +2470,8 @@ static PyMethodDef bufferedwriter_methods[] = { static PyMemberDef bufferedwriter_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(buffered, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(buffered, dict), READONLY}, {NULL} }; @@ -2494,58 +2483,26 @@ static PyGetSetDef bufferedwriter_getset[] = { }; -PyTypeObject PyBufferedWriter_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BufferedWriter", /*tp_name*/ - sizeof(buffered), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)buffered_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - (reprfunc)buffered_repr, /*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*/ - _io_BufferedWriter___init____doc__, /* tp_doc */ - (traverseproc)buffered_traverse, /* tp_traverse */ - (inquiry)buffered_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - bufferedwriter_methods, /* tp_methods */ - bufferedwriter_members, /* tp_members */ - bufferedwriter_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(buffered, dict), /* tp_dictoffset */ - _io_BufferedWriter___init__, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot bufferedwriter_slots[] = { + {Py_tp_dealloc, buffered_dealloc}, + {Py_tp_repr, buffered_repr}, + {Py_tp_doc, (void *)_io_BufferedWriter___init____doc__}, + {Py_tp_traverse, buffered_traverse}, + {Py_tp_clear, buffered_clear}, + {Py_tp_methods, bufferedwriter_methods}, + {Py_tp_members, bufferedwriter_members}, + {Py_tp_getset, bufferedwriter_getset}, + {Py_tp_init, _io_BufferedWriter___init__}, + {0, NULL}, }; +PyType_Spec bufferedwriter_spec = { + .name = "_io.BufferedWriter", + .basicsize = sizeof(buffered), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = bufferedwriter_slots, +}; static PyMethodDef bufferedrwpair_methods[] = { {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS}, @@ -2566,61 +2523,35 @@ static PyMethodDef bufferedrwpair_methods[] = { {NULL, NULL} }; +static PyMemberDef bufferedrwpair_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(rwpair, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(rwpair, dict), READONLY}, + {NULL} +}; + static PyGetSetDef bufferedrwpair_getset[] = { {"closed", (getter)bufferedrwpair_closed_get, NULL, NULL}, {NULL} }; -PyTypeObject PyBufferedRWPair_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BufferedRWPair", /*tp_name*/ - sizeof(rwpair), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)bufferedrwpair_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 */ - _io_BufferedRWPair___init____doc__, /* tp_doc */ - (traverseproc)bufferedrwpair_traverse, /* tp_traverse */ - (inquiry)bufferedrwpair_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(rwpair, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - bufferedrwpair_methods, /* tp_methods */ - 0, /* tp_members */ - bufferedrwpair_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(rwpair, dict), /* tp_dictoffset */ - _io_BufferedRWPair___init__, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot bufferedrwpair_slots[] = { + {Py_tp_dealloc, bufferedrwpair_dealloc}, + {Py_tp_doc, (void *)_io_BufferedRWPair___init____doc__}, + {Py_tp_traverse, bufferedrwpair_traverse}, + {Py_tp_clear, bufferedrwpair_clear}, + {Py_tp_methods, bufferedrwpair_methods}, + {Py_tp_members, bufferedrwpair_members}, + {Py_tp_getset, bufferedrwpair_getset}, + {Py_tp_init, _io_BufferedRWPair___init__}, + {0, NULL}, +}; + +PyType_Spec bufferedrwpair_spec = { + .name = "_io.BufferedRWPair", + .basicsize = sizeof(rwpair), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = bufferedrwpair_slots, }; @@ -2654,6 +2585,8 @@ static PyMethodDef bufferedrandom_methods[] = { static PyMemberDef bufferedrandom_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(buffered, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(buffered, dict), READONLY}, {NULL} }; @@ -2665,54 +2598,24 @@ static PyGetSetDef bufferedrandom_getset[] = { }; -PyTypeObject PyBufferedRandom_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BufferedRandom", /*tp_name*/ - sizeof(buffered), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)buffered_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - (reprfunc)buffered_repr, /*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*/ - _io_BufferedRandom___init____doc__, /* tp_doc */ - (traverseproc)buffered_traverse, /* tp_traverse */ - (inquiry)buffered_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - (iternextfunc)buffered_iternext, /* tp_iternext */ - bufferedrandom_methods, /* tp_methods */ - bufferedrandom_members, /* tp_members */ - bufferedrandom_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /*tp_dict*/ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(buffered, dict), /*tp_dictoffset*/ - _io_BufferedRandom___init__, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot bufferedrandom_slots[] = { + {Py_tp_dealloc, buffered_dealloc}, + {Py_tp_repr, buffered_repr}, + {Py_tp_doc, (void *)_io_BufferedRandom___init____doc__}, + {Py_tp_traverse, buffered_traverse}, + {Py_tp_clear, buffered_clear}, + {Py_tp_iternext, buffered_iternext}, + {Py_tp_methods, bufferedrandom_methods}, + {Py_tp_members, bufferedrandom_members}, + {Py_tp_getset, bufferedrandom_getset}, + {Py_tp_init, _io_BufferedRandom___init__}, + {0, NULL}, +}; + +PyType_Spec bufferedrandom_spec = { + .name = "_io.BufferedRandom", + .basicsize = sizeof(buffered), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = bufferedrandom_slots, }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 38ea756879c122..d44321bb8b960e 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -601,7 +601,7 @@ static int _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - PyTypeObject *base_tp = &PyBufferedRWPair_Type; + PyTypeObject *base_tp = clinic_state()->PyBufferedRWPair_Type; PyObject *reader; PyObject *writer; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; @@ -714,4 +714,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=953f1577e96e8d86 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8412b10c04259bb8 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 36e3b30de97d07..9777b7614ef057 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -53,7 +53,7 @@ module _io class _io.FileIO "fileio *" "clinic_state()->PyFileIO_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ac25ec278f4d6703]*/ typedef struct { PyObject_HEAD diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 7080ba935d9cc0..88198c795d3e49 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1178,9 +1178,9 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, Py_CLEAR(codec_info); _PyIO_State *state = IO_STATE(); - if (Py_IS_TYPE(buffer, &PyBufferedReader_Type) || - Py_IS_TYPE(buffer, &PyBufferedWriter_Type) || - Py_IS_TYPE(buffer, &PyBufferedRandom_Type)) + if (Py_IS_TYPE(buffer, state->PyBufferedReader_Type) || + Py_IS_TYPE(buffer, state->PyBufferedWriter_Type) || + Py_IS_TYPE(buffer, state->PyBufferedRandom_Type)) { if (_PyObject_LookupAttr(buffer, &_Py_ID(raw), &raw) < 0) goto error; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index a7582e6ee89b66..2cccbf18856104 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -317,10 +317,6 @@ Modules/_collectionsmodule.c - dequeiter_type - Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/bufferedio.c - PyBufferedIOBase_Type - -Modules/_io/bufferedio.c - PyBufferedRWPair_Type - -Modules/_io/bufferedio.c - PyBufferedRandom_Type - -Modules/_io/bufferedio.c - PyBufferedReader_Type - -Modules/_io/bufferedio.c - PyBufferedWriter_Type - Modules/_io/bytesio.c - PyBytesIO_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - From eeb5c48dec9be5de95130a8de9984d3ff9961905 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Feb 2023 13:22:53 +0100 Subject: [PATCH 07/54] PyBytesIO type --- Modules/_io/_iomodule.c | 5 +- Modules/_io/_iomodule.h | 3 +- Modules/_io/bytesio.c | 75 +++++++++------------ Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index e1ccb4d34c140a..1addab56abc4f3 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -642,9 +642,6 @@ static PyTypeObject* static_types[] = { &PyRawIOBase_Type, &PyTextIOBase_Type, - // PyBufferedIOBase_Type(PyIOBase_Type) subclasses - &PyBytesIO_Type, - // PyRawIOBase_Type(PyIOBase_Type) subclasses &_PyBytesIOBuffer_Type, #ifdef MS_WINDOWS @@ -705,7 +702,6 @@ PyInit__io(void) } // Set type base classes - PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type; #ifdef MS_WINDOWS PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; #endif @@ -719,6 +715,7 @@ PyInit__io(void) } // PyBufferedIOBase_Type(PyIOBase_Type) subclasses + ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, &PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, &PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec, diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 67a88a6969e103..354788093f2e88 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -14,7 +14,6 @@ extern PyTypeObject PyBufferedIOBase_Type; extern PyTypeObject PyTextIOBase_Type; /* Concrete classes */ -extern PyTypeObject PyBytesIO_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; /* Type specs */ @@ -22,6 +21,7 @@ extern PyType_Spec bufferedrandom_spec; extern PyType_Spec bufferedreader_spec; extern PyType_Spec bufferedrwpair_spec; extern PyType_Spec bufferedwriter_spec; +extern PyType_Spec bytesio_spec; extern PyType_Spec fileio_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiowrapper_spec; @@ -151,6 +151,7 @@ typedef struct { PyTypeObject *PyBufferedRandom_Type; PyTypeObject *PyBufferedReader_Type; PyTypeObject *PyBufferedWriter_Type; + PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOWrapper_Type; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 6698c60355fcc5..ec5de6ffa4a670 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -5,7 +5,7 @@ /*[clinic input] module _io -class _io.BytesIO "bytesio *" "&PyBytesIO_Type" +class _io.BytesIO "bytesio *" "clinic_state()->PyBytesIO_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=7f50ec034f5c0b26]*/ @@ -881,6 +881,7 @@ bytesio_setstate(bytesio *self, PyObject *state) static void bytesio_dealloc(bytesio *self) { + PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); if (self->exports > 0) { PyErr_SetString(PyExc_SystemError, @@ -891,7 +892,8 @@ bytesio_dealloc(bytesio *self) Py_CLEAR(self->dict); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); - Py_TYPE(self)->tp_free(self); + tp->tp_free(self); + Py_DECREF(tp); } static PyObject * @@ -971,6 +973,7 @@ bytesio_sizeof(bytesio *self, void *unused) static int bytesio_traverse(bytesio *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } @@ -983,7 +986,9 @@ bytesio_clear(bytesio *self) } +#define clinic_state() (IO_STATE()) #include "clinic/bytesio.c.h" +#undef clinic_state static PyGetSetDef bytesio_getsetlist[] = { {"closed", (getter)bytesio_get_closed, NULL, @@ -1016,48 +1021,34 @@ static struct PyMethodDef bytesio_methods[] = { {NULL, NULL} /* sentinel */ }; -PyTypeObject PyBytesIO_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BytesIO", /*tp_name*/ - sizeof(bytesio), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)bytesio_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*/ - _io_BytesIO___init____doc__, /*tp_doc*/ - (traverseproc)bytesio_traverse, /*tp_traverse*/ - (inquiry)bytesio_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - offsetof(bytesio, weakreflist), /*tp_weaklistoffset*/ - PyObject_SelfIter, /*tp_iter*/ - (iternextfunc)bytesio_iternext, /*tp_iternext*/ - bytesio_methods, /*tp_methods*/ - 0, /*tp_members*/ - bytesio_getsetlist, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - offsetof(bytesio, dict), /*tp_dictoffset*/ - _io_BytesIO___init__, /*tp_init*/ - 0, /*tp_alloc*/ - bytesio_new, /*tp_new*/ +static PyMemberDef bytesio_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(bytesio, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(bytesio, dict), READONLY}, + {NULL} }; +static PyType_Slot bytesio_slots[] = { + {Py_tp_dealloc, bytesio_dealloc}, + {Py_tp_doc, (void *)_io_BytesIO___init____doc__}, + {Py_tp_traverse, bytesio_traverse}, + {Py_tp_clear, bytesio_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, bytesio_iternext}, + {Py_tp_methods, bytesio_methods}, + {Py_tp_members, bytesio_members}, + {Py_tp_getset, bytesio_getsetlist}, + {Py_tp_init, _io_BytesIO___init__}, + {Py_tp_new, bytesio_new}, + {0, NULL}, +}; + +PyType_Spec bytesio_spec = { + .name = "_io.BytesIO", + .basicsize = sizeof(bytesio), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = bytesio_slots, +}; /* * Implementation of the small intermediate object used by getbuffer(). diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 2cccbf18856104..2e28c50c6ff69a 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -317,7 +317,6 @@ Modules/_collectionsmodule.c - dequeiter_type - Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/bufferedio.c - PyBufferedIOBase_Type - -Modules/_io/bytesio.c - PyBytesIO_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - From 4106c1b3b5549cef81059514eb0b4a1550de361e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Feb 2023 14:31:27 +0100 Subject: [PATCH 08/54] PyTextIOBase type --- Modules/_io/_iomodule.c | 10 +-- Modules/_io/_iomodule.h | 3 +- Modules/_io/textio.c | 77 ++++++++------------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 36 insertions(+), 55 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1addab56abc4f3..0bc46006a4d3ff 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -640,7 +640,6 @@ static PyTypeObject* static_types[] = { // PyIOBase_Type subclasses &PyBufferedIOBase_Type, &PyRawIOBase_Type, - &PyTextIOBase_Type, // PyRawIOBase_Type(PyIOBase_Type) subclasses &_PyBytesIOBuffer_Type, @@ -714,6 +713,9 @@ PyInit__io(void) } } + // PyIOBase_Type subclasses + ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, &PyIOBase_Type); + // PyBufferedIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, &PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, @@ -729,9 +731,9 @@ PyInit__io(void) ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); // PyTextIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, &PyTextIOBase_Type); - ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, - &PyTextIOBase_Type); + PyTypeObject *base = state->PyTextIOBase_Type; + ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, base); + ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, base); state->initialized = 1; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 354788093f2e88..477474a1bf3ba4 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -11,7 +11,6 @@ extern PyTypeObject PyIOBase_Type; extern PyTypeObject PyRawIOBase_Type; extern PyTypeObject PyBufferedIOBase_Type; -extern PyTypeObject PyTextIOBase_Type; /* Concrete classes */ extern PyTypeObject PyIncrementalNewlineDecoder_Type; @@ -24,6 +23,7 @@ extern PyType_Spec bufferedwriter_spec; extern PyType_Spec bytesio_spec; extern PyType_Spec fileio_spec; extern PyType_Spec stringio_spec; +extern PyType_Spec textiobase_spec; extern PyType_Spec textiowrapper_spec; #ifdef MS_WINDOWS @@ -154,6 +154,7 @@ typedef struct { PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyStringIO_Type; + PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; } _PyIO_State; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 88198c795d3e49..37ffdc572447e5 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -130,6 +130,21 @@ 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 void +textiobase_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} static PyMethodDef textiobase_methods[] = { {"detach", textiobase_detach, METH_NOARGS, textiobase_detach_doc}, @@ -146,57 +161,21 @@ 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_dealloc, textiobase_dealloc}, + {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 */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 2e28c50c6ff69a..1a25b60c278301 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -321,7 +321,6 @@ Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_io/textio.c - PyIncrementalNewlineDecoder_Type - -Modules/_io/textio.c - PyTextIOBase_Type - Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - From 3eba87322b26c55be0c3ee218b05625c98ed362e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Feb 2023 23:04:57 +0100 Subject: [PATCH 09/54] PyBufferedIOBase type --- Modules/_io/_iomodule.c | 22 +++--- Modules/_io/_iomodule.h | 3 +- Modules/_io/bufferedio.c | 82 ++++++++------------- Modules/_io/bytesio.c | 2 +- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 5 files changed, 43 insertions(+), 67 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 0bc46006a4d3ff..e4ecaba605b3bf 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -638,7 +638,6 @@ static PyTypeObject* static_types[] = { &PyIncrementalNewlineDecoder_Type, // PyIOBase_Type subclasses - &PyBufferedIOBase_Type, &PyRawIOBase_Type, // PyRawIOBase_Type(PyIOBase_Type) subclasses @@ -714,24 +713,23 @@ PyInit__io(void) } // PyIOBase_Type subclasses - ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, &PyIOBase_Type); + PyTypeObject *base = &PyIOBase_Type; + ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, base); + ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec, base); // PyBufferedIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, &PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, - &PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec, - &PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec, - &PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, - &PyBufferedIOBase_Type); + base = state->PyBufferedIOBase_Type; + ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, base); + ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, base); + ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec, base); + ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec, base); + ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, base); // PyRawIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); // PyTextIOBase_Type(PyIOBase_Type) subclasses - PyTypeObject *base = state->PyTextIOBase_Type; + base = state->PyTextIOBase_Type; ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, base); ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, base); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 477474a1bf3ba4..7f49971431f063 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -10,12 +10,12 @@ /* ABCs */ extern PyTypeObject PyIOBase_Type; extern PyTypeObject PyRawIOBase_Type; -extern PyTypeObject PyBufferedIOBase_Type; /* Concrete classes */ extern PyTypeObject PyIncrementalNewlineDecoder_Type; /* Type specs */ +extern PyType_Spec bufferediobase_spec; extern PyType_Spec bufferedrandom_spec; extern PyType_Spec bufferedreader_spec; extern PyType_Spec bufferedrwpair_spec; @@ -147,6 +147,7 @@ typedef struct { PyObject *unsupported_operation; /* Types */ + PyTypeObject *PyBufferedIOBase_Type; PyTypeObject *PyBufferedRWPair_Type; PyTypeObject *PyBufferedRandom_Type; PyTypeObject *PyBufferedReader_Type; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index ad9c1dfa0a0684..706c694dc9a9d3 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. @@ -2323,6 +2323,21 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, #include "clinic/bufferedio.c.h" #undef clinic_state +static void +bufferediobase_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +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 @@ -2334,57 +2349,20 @@ 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_dealloc, bufferediobase_dealloc}, + {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 */ diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index ec5de6ffa4a670..2cbc5260aa4aef 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -7,7 +7,7 @@ module _io class _io.BytesIO "bytesio *" "clinic_state()->PyBytesIO_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7f50ec034f5c0b26]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=48ede2f330f847c3]*/ typedef struct { PyObject_HEAD diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 1a25b60c278301..67cedd199e9388 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -316,7 +316,6 @@ Modules/_collectionsmodule.c - deque_type - Modules/_collectionsmodule.c - dequeiter_type - Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - -Modules/_io/bufferedio.c - PyBufferedIOBase_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - From de3acf0395fbc5c26983530a4d3d43ebd0140409 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 13 Feb 2023 09:06:33 +0100 Subject: [PATCH 10/54] PyIncrementalNewlineDecoder type --- Modules/_io/_iomodule.c | 4 +- Modules/_io/_iomodule.h | 5 +- Modules/_io/stringio.c | 3 +- Modules/_io/textio.c | 95 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 5 files changed, 55 insertions(+), 53 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index e4ecaba605b3bf..317ad7431c16c6 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -635,7 +635,6 @@ struct PyModuleDef _PyIO_Module = { static PyTypeObject* static_types[] = { // Base classes &PyIOBase_Type, - &PyIncrementalNewlineDecoder_Type, // PyIOBase_Type subclasses &PyRawIOBase_Type, @@ -712,6 +711,9 @@ PyInit__io(void) } } + // Concrete classes + ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); + // PyIOBase_Type subclasses PyTypeObject *base = &PyIOBase_Type; ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, base); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 7f49971431f063..5c39192f8bff09 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -11,9 +11,6 @@ extern PyTypeObject PyIOBase_Type; extern PyTypeObject PyRawIOBase_Type; -/* Concrete classes */ -extern PyTypeObject PyIncrementalNewlineDecoder_Type; - /* Type specs */ extern PyType_Spec bufferediobase_spec; extern PyType_Spec bufferedrandom_spec; @@ -22,6 +19,7 @@ extern PyType_Spec bufferedrwpair_spec; extern PyType_Spec bufferedwriter_spec; extern PyType_Spec bytesio_spec; extern PyType_Spec fileio_spec; +extern PyType_Spec nldecoder_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiobase_spec; extern PyType_Spec textiowrapper_spec; @@ -154,6 +152,7 @@ typedef struct { PyTypeObject *PyBufferedWriter_Type; PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; + PyTypeObject *PyIncrementalNewlineDecoder_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 12ae5a09ca70a2..e0f3b6d8d26804 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -717,8 +717,9 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, } if (self->readuniversal) { + _PyIO_State *state = IO_STATE(); self->decoder = PyObject_CallFunctionObjArgs( - (PyObject *)&PyIncrementalNewlineDecoder_Type, + (PyObject *)state->PyIncrementalNewlineDecoder_Type, Py_None, self->readtranslate ? Py_True : Py_False, NULL); if (self->decoder == NULL) return -1; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 37ffdc572447e5..1b0a310fc6191c 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -18,10 +18,10 @@ /*[clinic input] module _io -class _io.IncrementalNewlineDecoder "nldecoder_object *" "&PyIncrementalNewlineDecoder_Type" +class _io.IncrementalNewlineDecoder "nldecoder_object *" "clinic_state()->PyIncrementalNewlineDecoder_Type" class _io.TextIOWrapper "textio *" "clinic_state()->TextIOWrapper_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d3f032e90f74c8f2]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81f67cf54eaa6001]*/ /* TextIOBase */ @@ -227,12 +227,32 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self, return 0; } -static void -incrementalnewlinedecoder_dealloc(nldecoder_object *self) +static int +incrementalnewlinedecoder_traverse(nldecoder_object *self, visitproc visit, + void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->decoder); + Py_VISIT(self->errors); + return 0; +} + +static int +incrementalnewlinedecoder_clear(nldecoder_object *self) { Py_CLEAR(self->decoder); Py_CLEAR(self->errors); - Py_TYPE(self)->tp_free((PyObject *)self); + return 0; +} + +static void +incrementalnewlinedecoder_dealloc(nldecoder_object *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + (void)incrementalnewlinedecoder_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static int @@ -851,8 +871,9 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, return -1; if (self->readuniversal) { + _PyIO_State *state = IO_STATE(); PyObject *incrementalDecoder = PyObject_CallFunctionObjArgs( - (PyObject *)&PyIncrementalNewlineDecoder_Type, + (PyObject *)state->PyIncrementalNewlineDecoder_Type, self->decoder, self->readtranslate ? Py_True : Py_False, NULL); if (incrementalDecoder == NULL) return -1; @@ -867,7 +888,8 @@ _textiowrapper_decode(PyObject *decoder, PyObject *bytes, int eof) { PyObject *chars; - if (Py_IS_TYPE(decoder, &PyIncrementalNewlineDecoder_Type)) + _PyIO_State *state = IO_STATE(); + if (Py_IS_TYPE(decoder, state->PyIncrementalNewlineDecoder_Type)) chars = _PyIncrementalNewlineDecoder_decode(decoder, bytes, eof); else chars = PyObject_CallMethodObjArgs(decoder, &_Py_ID(decode), bytes, @@ -1892,7 +1914,8 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) if (bytes == NULL) goto fail; - if (Py_IS_TYPE(self->decoder, &PyIncrementalNewlineDecoder_Type)) + _PyIO_State *state = self->state; + if (Py_IS_TYPE(self->decoder, state->PyIncrementalNewlineDecoder_Type)) decoded = _PyIncrementalNewlineDecoder_decode(self->decoder, bytes, 1); else @@ -3149,45 +3172,23 @@ static PyGetSetDef incrementalnewlinedecoder_getset[] = { {NULL} }; -PyTypeObject PyIncrementalNewlineDecoder_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.IncrementalNewlineDecoder", /*tp_name*/ - sizeof(nldecoder_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)incrementalnewlinedecoder_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, /*tp_flags*/ - _io_IncrementalNewlineDecoder___init____doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /*tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - incrementalnewlinedecoder_methods, /* tp_methods */ - 0, /* tp_members */ - incrementalnewlinedecoder_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - _io_IncrementalNewlineDecoder___init__, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot nldecoder_slots[] = { + {Py_tp_dealloc, incrementalnewlinedecoder_dealloc}, + {Py_tp_doc, (void *)_io_IncrementalNewlineDecoder___init____doc__}, + {Py_tp_methods, incrementalnewlinedecoder_methods}, + {Py_tp_getset, incrementalnewlinedecoder_getset}, + {Py_tp_traverse, incrementalnewlinedecoder_traverse}, + {Py_tp_clear, incrementalnewlinedecoder_clear}, + {Py_tp_init, _io_IncrementalNewlineDecoder___init__}, + {0, NULL}, +}; + +PyType_Spec nldecoder_spec = { + .name = "_io.IncrementalNewlineDecoder", + .basicsize = sizeof(nldecoder_object), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = nldecoder_slots, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 67cedd199e9388..a15e42717c35f1 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -319,7 +319,6 @@ Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - -Modules/_io/textio.c - PyIncrementalNewlineDecoder_Type - Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - From bc3521868b0e4776cddeee0c40b97cd417da8f20 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 11:35:29 +0100 Subject: [PATCH 11/54] PyBytesIOBuffer type --- Modules/_io/_iomodule.c | 4 +- Modules/_io/_iomodule.h | 4 +- Modules/_io/bytesio.c | 64 +++++++-------------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 23 insertions(+), 50 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 317ad7431c16c6..ee00d1ec9a46bd 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -638,9 +638,6 @@ static PyTypeObject* static_types[] = { // PyIOBase_Type subclasses &PyRawIOBase_Type, - - // PyRawIOBase_Type(PyIOBase_Type) subclasses - &_PyBytesIOBuffer_Type, #ifdef MS_WINDOWS &PyWindowsConsoleIO_Type, #endif @@ -729,6 +726,7 @@ PyInit__io(void) // PyRawIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); + ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); // XXX: should be subclass of PyRawIOBase_Type? // PyTextIOBase_Type(PyIOBase_Type) subclasses base = state->PyTextIOBase_Type; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 5c39192f8bff09..aced6fb1cdd9cd 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -18,6 +18,7 @@ extern PyType_Spec bufferedreader_spec; extern PyType_Spec bufferedrwpair_spec; extern PyType_Spec bufferedwriter_spec; extern PyType_Spec bytesio_spec; +extern PyType_Spec bytesiobuf_spec; extern PyType_Spec fileio_spec; extern PyType_Spec nldecoder_spec; extern PyType_Spec stringio_spec; @@ -150,6 +151,7 @@ typedef struct { PyTypeObject *PyBufferedRandom_Type; PyTypeObject *PyBufferedReader_Type; PyTypeObject *PyBufferedWriter_Type; + PyTypeObject *PyBytesIOBuffer_Type; PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyIncrementalNewlineDecoder_Type; @@ -174,5 +176,3 @@ extern _PyIO_State *_PyIO_get_module_state(void); #ifdef MS_WINDOWS extern char _PyIO_get_console_type(PyObject *); #endif - -extern Py_EXPORTED_SYMBOL PyTypeObject _PyBytesIOBuffer_Type; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 2cbc5260aa4aef..84db3c03084135 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -315,7 +315,8 @@ static PyObject * _io_BytesIO_getbuffer_impl(bytesio *self) /*[clinic end generated code: output=72cd7c6e13aa09ed input=8f738ef615865176]*/ { - PyTypeObject *type = &_PyBytesIOBuffer_Type; + _PyIO_State *state = IO_STATE(); + PyTypeObject *type = state->PyBytesIOBuffer_Type; bytesiobuf *buf; PyObject *view; @@ -1089,6 +1090,7 @@ bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view) static int bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->source); return 0; } @@ -1096,54 +1098,28 @@ bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) static void bytesiobuf_dealloc(bytesiobuf *self) { + PyTypeObject *tp = Py_TYPE(self); /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(self); Py_CLEAR(self->source); - Py_TYPE(self)->tp_free(self); + tp->tp_free(self); + Py_DECREF(tp); } -static PyBufferProcs bytesiobuf_as_buffer = { - (getbufferproc) bytesiobuf_getbuffer, - (releasebufferproc) bytesiobuf_releasebuffer, +static PyType_Slot bytesiobuf_slots[] = { + {Py_tp_dealloc, bytesiobuf_dealloc}, + {Py_tp_traverse, bytesiobuf_traverse}, + + // Buffer protocol + {Py_bf_getbuffer, bytesiobuf_getbuffer}, + {Py_bf_releasebuffer, bytesiobuf_releasebuffer}, + {0, NULL}, }; -Py_EXPORTED_SYMBOL PyTypeObject _PyBytesIOBuffer_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._BytesIOBuffer", /*tp_name*/ - sizeof(bytesiobuf), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)bytesiobuf_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*/ - &bytesiobuf_as_buffer, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - (traverseproc)bytesiobuf_traverse, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*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*/ +PyType_Spec bytesiobuf_spec = { + .name = "_io._BytesIOBuffer", + .basicsize = sizeof(bytesiobuf), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), + .slots = bytesiobuf_slots, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index a15e42717c35f1..cf118f82a1216b 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -316,7 +316,6 @@ Modules/_collectionsmodule.c - deque_type - Modules/_collectionsmodule.c - dequeiter_type - Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - -Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - From 62a91e9775a6c1a7e6e82aba4c122f8adc910e81 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 23:12:24 +0100 Subject: [PATCH 12/54] PyWindowsConsoleIO type --- Modules/_io/_iomodule.c | 16 ++-- Modules/_io/_iomodule.h | 8 +- Modules/_io/winconsoleio.c | 82 ++++++++------------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 41 insertions(+), 66 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ee00d1ec9a46bd..ea25c9ef9ac031 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -320,7 +320,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, #ifdef MS_WINDOWS const PyConfig *config = _Py_GetConfig(); if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') { - RawIO_class = (PyObject *)&PyWindowsConsoleIO_Type; + RawIO_class = (PyObject *)state->PyWindowsConsoleIO_Type; encoding = "utf-8"; } #endif @@ -638,9 +638,6 @@ static PyTypeObject* static_types[] = { // PyIOBase_Type subclasses &PyRawIOBase_Type, -#ifdef MS_WINDOWS - &PyWindowsConsoleIO_Type, -#endif }; @@ -695,11 +692,6 @@ PyInit__io(void) goto fail; } - // Set type base classes -#ifdef MS_WINDOWS - PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; -#endif - // Add types for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; @@ -725,8 +717,12 @@ PyInit__io(void) ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, base); // PyRawIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); + base = &PyRawIOBase_Type; + ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, base); ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); // XXX: should be subclass of PyRawIOBase_Type? +#ifdef MS_WINDOWS + ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, base); +#endif // PyTextIOBase_Type(PyIOBase_Type) subclasses base = state->PyTextIOBase_Type; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index aced6fb1cdd9cd..b634bdadbed422 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -24,10 +24,9 @@ extern PyType_Spec nldecoder_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiobase_spec; extern PyType_Spec textiowrapper_spec; - #ifdef MS_WINDOWS -extern PyTypeObject PyWindowsConsoleIO_Type; -#endif /* MS_WINDOWS */ +extern PyType_Spec winconsoleio_spec; +#endif /* These functions are used as METH_NOARGS methods, are normally called * with args=NULL, and return a new reference. @@ -158,6 +157,9 @@ typedef struct { PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; +#ifdef MS_WINDOWS + PyTypeObject *PyWindowsConsoleIO_Type; +#endif } _PyIO_State; #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index e913d831874617..030ed728111497 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -135,7 +135,7 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { /*[clinic input] module _io -class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" +class _io._WindowsConsoleIO "winconsoleio *" "clinic_state()->PyWindowsConsoleIO_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e897fdc1fba4e131]*/ @@ -412,6 +412,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, static int winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } @@ -426,6 +427,7 @@ winconsoleio_clear(winconsoleio *self) static void winconsoleio_dealloc(winconsoleio *self) { + PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; @@ -433,7 +435,8 @@ winconsoleio_dealloc(winconsoleio *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); } static PyObject * @@ -1073,7 +1076,9 @@ _io__WindowsConsoleIO_isatty_impl(winconsoleio *self) Py_RETURN_TRUE; } +#define clinic_state() (IO_STATE()) #include "clinic/winconsoleio.c.h" +#undef clinic_state static PyMethodDef winconsoleio_methods[] = { _IO__WINDOWSCONSOLEIO_READ_METHODDEF @@ -1119,59 +1124,32 @@ static PyGetSetDef winconsoleio_getsetlist[] = { static PyMemberDef winconsoleio_members[] = { {"_blksize", T_UINT, offsetof(winconsoleio, blksize), 0}, {"_finalizing", T_BOOL, offsetof(winconsoleio, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(winconsoleio, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(winconsoleio, dict), READONLY}, {NULL} }; -PyTypeObject PyWindowsConsoleIO_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._WindowsConsoleIO", - sizeof(winconsoleio), - 0, - (destructor)winconsoleio_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)winconsoleio_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - _io__WindowsConsoleIO___init____doc__, /* tp_doc */ - (traverseproc)winconsoleio_traverse, /* tp_traverse */ - (inquiry)winconsoleio_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(winconsoleio, weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - winconsoleio_methods, /* tp_methods */ - winconsoleio_members, /* tp_members */ - winconsoleio_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(winconsoleio, dict), /* tp_dictoffset */ - _io__WindowsConsoleIO___init__, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - winconsoleio_new, /* tp_new */ - PyObject_GC_Del, /* 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 winconsoleio_slots[] = { + {Py_tp_dealloc, winconsoleio_dealloc}, + {Py_tp_repr, winconsoleio_repr}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)_io__WindowsConsoleIO___init____doc__}, + {Py_tp_traverse, winconsoleio_traverse}, + {Py_tp_clear, winconsoleio_clear}, + {Py_tp_methods, winconsoleio_methods}, + {Py_tp_members, winconsoleio_members}, + {Py_tp_getset, winconsoleio_getsetlist}, + {Py_tp_init, _io__WindowsConsoleIO___init__}, + {Py_tp_new, winconsoleio_new}, + {0, NULL}, +}; + +PyType_Spec winconsoleio_spec = { + .name = "_io._WindowsConsoleIO", + .basicsize = sizeof(winconsoleio), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = winconsoleio_slots, }; #endif /* MS_WINDOWS */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index cf118f82a1216b..c6b0a7f5b742a0 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -318,7 +318,6 @@ Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - -Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type - From 23b79ebc8c017b0cb9297da473f9ba3f0e135f5a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 23:25:45 +0100 Subject: [PATCH 13/54] RawIOBase type --- Modules/_io/_iomodule.c | 6 +- Modules/_io/_iomodule.h | 3 +- Modules/_io/fileio.c | 4 +- Modules/_io/iobase.c | 84 ++++++++------------- Modules/_io/winconsoleio.c | 6 +- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 6 files changed, 44 insertions(+), 60 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ea25c9ef9ac031..0f4181c28b05a0 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -635,9 +635,6 @@ struct PyModuleDef _PyIO_Module = { static PyTypeObject* static_types[] = { // Base classes &PyIOBase_Type, - - // PyIOBase_Type subclasses - &PyRawIOBase_Type, }; @@ -707,6 +704,7 @@ PyInit__io(void) PyTypeObject *base = &PyIOBase_Type; ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, base); ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec, base); + ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec, base); // PyBufferedIOBase_Type(PyIOBase_Type) subclasses base = state->PyBufferedIOBase_Type; @@ -717,7 +715,7 @@ PyInit__io(void) ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, base); // PyRawIOBase_Type(PyIOBase_Type) subclasses - base = &PyRawIOBase_Type; + base = state->PyRawIOBase_Type; ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, base); ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); // XXX: should be subclass of PyRawIOBase_Type? #ifdef MS_WINDOWS diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index b634bdadbed422..6020d1842bed58 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -9,7 +9,6 @@ /* ABCs */ extern PyTypeObject PyIOBase_Type; -extern PyTypeObject PyRawIOBase_Type; /* Type specs */ extern PyType_Spec bufferediobase_spec; @@ -21,6 +20,7 @@ extern PyType_Spec bytesio_spec; extern PyType_Spec bytesiobuf_spec; extern PyType_Spec fileio_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; @@ -154,6 +154,7 @@ typedef struct { PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyIncrementalNewlineDecoder_Type; + PyTypeObject *PyRawIOBase_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 9777b7614ef057..15b2a9fe5639b5 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -142,7 +142,9 @@ _io_FileIO_close_impl(fileio *self) PyObject *res; PyObject *exc, *val, *tb; int rc; - res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type, + + _PyIO_State *state = IO_STATE(); + res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject *)self); if (!self->closefd) { self->fd = -1; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 7b9391ec54d732..2937690869d348 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -18,9 +18,9 @@ /*[clinic input] module _io class _io._IOBase "PyObject *" "&PyIOBase_Type" -class _io._RawIOBase "PyObject *" "&PyRawIOBase_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=248f8b2f8bd58b45]*/ /* * IOBase class, an abstract class @@ -786,7 +786,9 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines) Py_RETURN_NONE; } +#define clinic_state() (IO_STATE()) #include "clinic/iobase.c.h" +#undef clinic_state static PyMethodDef iobase_methods[] = { {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc}, @@ -1010,6 +1012,22 @@ rawiobase_write(PyObject *self, PyObject *args) return NULL; } +static void +rawiobase_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +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 @@ -1018,53 +1036,17 @@ 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_dealloc, rawiobase_dealloc}, + {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/winconsoleio.c b/Modules/_io/winconsoleio.c index 030ed728111497..6925f088ab7fba 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -137,7 +137,7 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { module _io class _io._WindowsConsoleIO "winconsoleio *" "clinic_state()->PyWindowsConsoleIO_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e897fdc1fba4e131]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=05526e723011ab36]*/ typedef struct { PyObject_HEAD @@ -194,7 +194,9 @@ _io__WindowsConsoleIO_close_impl(winconsoleio *self) PyObject *res; PyObject *exc, *val, *tb; int rc; - res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type, + + _PyIO_State *state = IO_STATE(); + res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject*)self); if (!self->closefd) { self->fd = -1; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index c6b0a7f5b742a0..26f37c630d257e 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -317,7 +317,6 @@ Modules/_collectionsmodule.c - dequeiter_type - Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/iobase.c - PyIOBase_Type - -Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type - From be64029e94e565aa0c1ef958460315814917c327 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 23:42:41 +0100 Subject: [PATCH 14/54] IOBase type --- Modules/_io/_iomodule.c | 24 ++---- Modules/_io/_iomodule.h | 5 +- Modules/_io/iobase.c | 84 ++++++++------------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 4 files changed, 38 insertions(+), 76 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 0f4181c28b05a0..1e3142d6f844d8 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -632,19 +632,10 @@ struct PyModuleDef _PyIO_Module = { }; -static PyTypeObject* static_types[] = { - // Base classes - &PyIOBase_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); - } + return; } #define ADD_TYPE(module, type, spec, base) \ @@ -689,19 +680,14 @@ PyInit__io(void) 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; - } - } - // Concrete classes ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); + // Base classes + ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL); + // PyIOBase_Type subclasses - PyTypeObject *base = &PyIOBase_Type; + PyTypeObject *base = state->PyIOBase_Type; ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, base); ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec, base); ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec, base); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 6020d1842bed58..67432afcf50a5b 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -7,9 +7,6 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" -/* ABCs */ -extern PyTypeObject PyIOBase_Type; - /* Type specs */ extern PyType_Spec bufferediobase_spec; extern PyType_Spec bufferedrandom_spec; @@ -19,6 +16,7 @@ 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; @@ -153,6 +151,7 @@ typedef struct { PyTypeObject *PyBytesIOBuffer_Type; PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; + PyTypeObject *PyIOBase_Type; PyTypeObject *PyIncrementalNewlineDecoder_Type; PyTypeObject *PyRawIOBase_Type; PyTypeObject *PyStringIO_Type; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 2937690869d348..98ee3d8c39bd1c 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._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=248f8b2f8bd58b45]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9006b7802ab8ea85]*/ /* * IOBase class, an abstract class @@ -319,6 +319,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; } @@ -348,11 +349,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 */ @@ -825,59 +828,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. diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 26f37c630d257e..3ea97aaaf825d9 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -316,7 +316,6 @@ Modules/_collectionsmodule.c - deque_type - Modules/_collectionsmodule.c - dequeiter_type - Modules/_collectionsmodule.c - dequereviter_type - Modules/_collectionsmodule.c - tuplegetter_type - -Modules/_io/iobase.c - PyIOBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type - From 55234a28035bce68e6cc31d48081afe783cfcad4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 23:43:54 +0100 Subject: [PATCH 15/54] Remove crud --- Modules/_io/_iomodule.c | 7 ------- Python/pylifecycle.c | 6 ------ 2 files changed, 13 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1e3142d6f844d8..cb516b98c12d3e 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -631,13 +631,6 @@ struct PyModuleDef _PyIO_Module = { (freefunc)iomodule_free, }; - -void -_PyIO_Fini(void) -{ - return; -} - #define ADD_TYPE(module, type, spec, base) \ do { \ type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 045a2996e8988b..83e17279307d57 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -31,8 +31,6 @@ #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" -extern void _PyIO_Fini(void); - #include // setlocale() #include // getenv() @@ -1767,10 +1765,6 @@ 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. */ From 0328a3490e7a6d1ee46ff4a2f5d5147dca4811ef Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 23:45:29 +0100 Subject: [PATCH 16/54] Fixup module def init --- Modules/_io/_iomodule.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index cb516b98c12d3e..c94890e0bfbac0 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -620,15 +620,14 @@ static PyMethodDef module_methods[] = { }; struct PyModuleDef _PyIO_Module = { - PyModuleDef_HEAD_INIT, - "io", - module_doc, - sizeof(_PyIO_State), - module_methods, - NULL, - iomodule_traverse, - iomodule_clear, - (freefunc)iomodule_free, + .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, }; #define ADD_TYPE(module, type, spec, base) \ From a83cf1f6906b7d87574b5f02730c35fb4ab98c4c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 16 Feb 2023 12:25:51 +0100 Subject: [PATCH 17/54] WIP module state / multi-phase init --- Modules/_io/_iomodule.c | 167 ++++++++++++++++------------ Modules/_io/_iomodule.h | 20 +++- Modules/_io/bufferedio.c | 45 ++++---- Modules/_io/bytesio.c | 11 +- Modules/_io/clinic/bufferedio.c.h | 43 +++++-- Modules/_io/clinic/bytesio.c.h | 14 ++- Modules/_io/clinic/fileio.c.h | 134 ++++++++++++++++------ Modules/_io/clinic/iobase.c.h | 14 ++- Modules/_io/clinic/winconsoleio.c.h | 75 ++++++++++--- Modules/_io/fileio.c | 62 ++++++----- Modules/_io/iobase.c | 33 +++--- Modules/_io/stringio.c | 6 +- Modules/_io/textio.c | 46 ++++---- Modules/_io/winconsoleio.c | 46 +++++--- 14 files changed, 465 insertions(+), 251 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index c94890e0bfbac0..14b0a28ba9ece3 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -386,7 +386,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, return result; } - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state(module); /* wraps into a buffered file */ { PyObject *Buffered_class; @@ -562,45 +562,65 @@ 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) { +iomodule_traverse(PyObject *mod, visitproc visit, void *arg) +{ _PyIO_State *state = get_io_state(mod); - if (!state->initialized) - return 0; Py_VISIT(state->locale_module); Py_VISIT(state->unsupported_operation); + + Py_VISIT(state->PyBufferedIOBase_Type); + Py_VISIT(state->PyBufferedRWPair_Type); + Py_VISIT(state->PyBufferedRandom_Type); + Py_VISIT(state->PyBufferedReader_Type); + Py_VISIT(state->PyBufferedWriter_Type); + Py_VISIT(state->PyBytesIOBuffer_Type); + Py_VISIT(state->PyBytesIO_Type); + Py_VISIT(state->PyFileIO_Type); + Py_VISIT(state->PyIOBase_Type); + Py_VISIT(state->PyIncrementalNewlineDecoder_Type); + Py_VISIT(state->PyRawIOBase_Type); + Py_VISIT(state->PyStringIO_Type); + Py_VISIT(state->PyTextIOBase_Type); + Py_VISIT(state->PyTextIOWrapper_Type); +#ifdef MS_WINDOWS + Py_VISIT(state->PyWindowsConsoleIO_Type); +#endif return 0; } static int -iomodule_clear(PyObject *mod) { +iomodule_clear(PyObject *mod) +{ _PyIO_State *state = get_io_state(mod); - if (!state->initialized) - return 0; - if (state->locale_module != NULL) - Py_CLEAR(state->locale_module); + Py_CLEAR(state->locale_module); Py_CLEAR(state->unsupported_operation); + + Py_CLEAR(state->PyBufferedIOBase_Type); + Py_CLEAR(state->PyBufferedRWPair_Type); + Py_CLEAR(state->PyBufferedRandom_Type); + Py_CLEAR(state->PyBufferedReader_Type); + Py_CLEAR(state->PyBufferedWriter_Type); + Py_CLEAR(state->PyBytesIOBuffer_Type); + Py_CLEAR(state->PyBytesIO_Type); + Py_CLEAR(state->PyFileIO_Type); + Py_CLEAR(state->PyIOBase_Type); + Py_CLEAR(state->PyIncrementalNewlineDecoder_Type); + Py_CLEAR(state->PyRawIOBase_Type); + Py_CLEAR(state->PyStringIO_Type); + Py_CLEAR(state->PyTextIOBase_Type); + Py_CLEAR(state->PyTextIOWrapper_Type); +#ifdef MS_WINDOWS + Py_CLEAR(state->PyWindowsConsoleIO_Type); +#endif return 0; } static void -iomodule_free(PyObject *mod) { - iomodule_clear(mod); +iomodule_free(void *mod) +{ + (void)iomodule_clear(mod); } @@ -608,7 +628,7 @@ iomodule_free(PyObject *mod) { * Module definition */ -#define clinic_state() (IO_STATE()) +#define clinic_state() (get_io_state(module)) #include "clinic/_iomodule.c.h" #undef clinic_state @@ -619,59 +639,48 @@ static PyMethodDef module_methods[] = { {NULL, 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, -}; - -#define ADD_TYPE(module, type, spec, base) \ -do { \ - type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ - (PyObject *)base); \ - if (type == NULL) { \ - goto fail; \ - } \ - if (PyModule_AddType(module, type) < 0) { \ - goto fail; \ - } \ -} 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; + if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) { + 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; + if (state->unsupported_operation == NULL) { + return -1; + } if (PyModule_AddObject(m, "UnsupportedOperation", Py_NewRef(state->unsupported_operation)) < 0) - goto fail; + { + return -1; + } /* BlockingIOError, for compatibility */ if (PyModule_AddObjectRef(m, "BlockingIOError", - (PyObject *) PyExc_BlockingIOError) < 0) { - goto fail; + (PyObject *) PyExc_BlockingIOError) < 0) + { + return -1; } +#define ADD_TYPE(module, type, spec, base) \ +do { \ + type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ + (PyObject *)base); \ + if (type == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(module, type) < 0) { \ + return -1; \ + } \ +} while (0) + // Concrete classes ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); @@ -705,12 +714,30 @@ PyInit__io(void) ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, base); ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, base); - state->initialized = 1; +#undef ADD_TYPE - return m; + return 0; +} - fail: - Py_XDECREF(state->unsupported_operation); - Py_DECREF(m); - return NULL; +static struct PyModuleDef_Slot iomodule_slots[] = { + {Py_mod_exec, iomodule_exec}, + {0, 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 67432afcf50a5b..e90bfd9e4d7ee1 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -137,7 +137,6 @@ extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err); extern PyModuleDef _PyIO_Module; typedef struct { - int initialized; PyObject *locale_module; PyObject *unsupported_operation; @@ -162,9 +161,6 @@ typedef struct { #endif } _PyIO_State; -#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) { @@ -173,7 +169,21 @@ get_io_state(PyObject *module) return (_PyIO_State *)state; } -extern _PyIO_State *_PyIO_get_module_state(void); +static inline _PyIO_State * +get_io_state_by_cls(PyTypeObject *cls) +{ + void *state = PyType_GetModuleState(cls); + assert(state != NULL); + return (_PyIO_State *)state; +} + +static inline _PyIO_State * +find_io_state_by_def(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &_PyIO_Module); + assert(mod != NULL); + return get_io_state(mod); +} #ifdef MS_WINDOWS extern char _PyIO_get_console_type(PyObject *); diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 706c694dc9a9d3..fc3815bbb2ff1a 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -106,17 +106,18 @@ _io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer) } static PyObject * -bufferediobase_unsupported(const char *message) +bufferediobase_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } /*[clinic input] _io._BufferedIOBase.detach + cls: defining_class + / + Disconnect this buffer from its underlying raw stream and return it. After the raw stream has been detached, the buffer is in an unusable @@ -124,10 +125,11 @@ state. [clinic start generated code]*/ static PyObject * -_io__BufferedIOBase_detach_impl(PyObject *self) -/*[clinic end generated code: output=754977c8d10ed88c input=822427fb58fe4169]*/ +_io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=b87b135d67cd4448 input=0b61a7b4357c1ea7]*/ { - return bufferediobase_unsupported("detach"); + _PyIO_State *state = get_io_state_by_cls(cls); + return bufferediobase_unsupported(state, "detach"); } PyDoc_STRVAR(bufferediobase_read_doc, @@ -151,7 +153,8 @@ PyDoc_STRVAR(bufferediobase_read_doc, static PyObject * bufferediobase_read(PyObject *self, PyObject *args) { - return bufferediobase_unsupported("read"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return bufferediobase_unsupported(state, "read"); } PyDoc_STRVAR(bufferediobase_read1_doc, @@ -164,7 +167,8 @@ PyDoc_STRVAR(bufferediobase_read1_doc, static PyObject * bufferediobase_read1(PyObject *self, PyObject *args) { - return bufferediobase_unsupported("read1"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return bufferediobase_unsupported(state, "read1"); } PyDoc_STRVAR(bufferediobase_write_doc, @@ -179,7 +183,8 @@ PyDoc_STRVAR(bufferediobase_write_doc, static PyObject * bufferediobase_write(PyObject *self, PyObject *args) { - return bufferediobase_unsupported("write"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return bufferediobase_unsupported(state, "write"); } @@ -1287,20 +1292,22 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) /*[clinic input] _io._Buffered.truncate + cls: defining_class pos: object = None / [clinic start generated code]*/ static PyObject * -_io__Buffered_truncate_impl(buffered *self, PyObject *pos) -/*[clinic end generated code: output=667ca03c60c270de input=8a1be34d57cca2d3]*/ +_io__Buffered_truncate_impl(buffered *self, PyTypeObject *cls, PyObject *pos) +/*[clinic end generated code: output=fe3882fbffe79f1a input=f5b737d97d76303f]*/ { PyObject *res = NULL; CHECK_INITIALIZED(self) CHECK_CLOSED(self, "truncate of closed file") if (!self->writable) { - return bufferediobase_unsupported("truncate"); + _PyIO_State *state = get_io_state_by_cls(cls); + return bufferediobase_unsupported(state, "truncate"); } if (!ENTER_BUFFERED(self)) return NULL; @@ -1331,7 +1338,7 @@ buffered_iternext(buffered *self) CHECK_INITIALIZED(self); - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); tp = Py_TYPE(self); if (Py_IS_TYPE(tp, state->PyBufferedReader_Type) || Py_IS_TYPE(tp, state->PyBufferedRandom_Type)) @@ -1433,7 +1440,7 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, return -1; _bufferedreader_reset_buf(self); - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = ( Py_IS_TYPE(self, state->PyBufferedReader_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type) @@ -1791,7 +1798,7 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = ( Py_IS_TYPE(self, state->PyBufferedWriter_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type) @@ -2101,7 +2108,7 @@ _io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, if (_PyIOBase_check_writable(writer, Py_True) == NULL) return -1; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->reader = (buffered *) PyObject_CallFunction( (PyObject *)state->PyBufferedReader_Type, "On", reader, buffer_size); @@ -2311,7 +2318,7 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = (Py_IS_TYPE(self, state->PyBufferedRandom_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type)); @@ -2319,7 +2326,7 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, return 0; } -#define clinic_state() (IO_STATE()) +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/bufferedio.c.h" #undef clinic_state diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 84db3c03084135..6a7d9fad8a2a83 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -308,14 +308,17 @@ _io_BytesIO_flush_impl(bytesio *self) /*[clinic input] _io.BytesIO.getbuffer + cls: defining_class + / + Get a read-write view over the contents of the BytesIO object. [clinic start generated code]*/ static PyObject * -_io_BytesIO_getbuffer_impl(bytesio *self) -/*[clinic end generated code: output=72cd7c6e13aa09ed input=8f738ef615865176]*/ +_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls) +/*[clinic end generated code: output=045091d7ce87fe4e input=0668fbb48f95dffa]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); PyTypeObject *type = state->PyBytesIOBuffer_Type; bytesiobuf *buf; PyObject *view; @@ -987,7 +990,7 @@ bytesio_clear(bytesio *self) } -#define clinic_state() (IO_STATE()) +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/bytesio.c.h" #undef clinic_state diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index d44321bb8b960e..f92bade7435f03 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -92,15 +92,19 @@ PyDoc_STRVAR(_io__BufferedIOBase_detach__doc__, "state."); #define _IO__BUFFEREDIOBASE_DETACH_METHODDEF \ - {"detach", (PyCFunction)_io__BufferedIOBase_detach, METH_NOARGS, _io__BufferedIOBase_detach__doc__}, + {"detach", _PyCFunction_CAST(_io__BufferedIOBase_detach), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__BufferedIOBase_detach__doc__}, static PyObject * -_io__BufferedIOBase_detach_impl(PyObject *self); +_io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_io__BufferedIOBase_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) +_io__BufferedIOBase_detach(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__BufferedIOBase_detach_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "detach() takes no arguments"); + return NULL; + } + return _io__BufferedIOBase_detach_impl(self, cls); } PyDoc_STRVAR(_io__Buffered_peek__doc__, @@ -369,26 +373,41 @@ PyDoc_STRVAR(_io__Buffered_truncate__doc__, "\n"); #define _IO__BUFFERED_TRUNCATE_METHODDEF \ - {"truncate", _PyCFunction_CAST(_io__Buffered_truncate), METH_FASTCALL, _io__Buffered_truncate__doc__}, + {"truncate", _PyCFunction_CAST(_io__Buffered_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__Buffered_truncate__doc__}, static PyObject * -_io__Buffered_truncate_impl(buffered *self, PyObject *pos); +_io__Buffered_truncate_impl(buffered *self, PyTypeObject *cls, PyObject *pos); static PyObject * -_io__Buffered_truncate(buffered *self, PyObject *const *args, Py_ssize_t nargs) +_io__Buffered_truncate(buffered *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "truncate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyObject *pos = Py_None; - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } pos = args[0]; -skip_optional: - return_value = _io__Buffered_truncate_impl(self, pos); +skip_optional_posonly: + return_value = _io__Buffered_truncate_impl(self, cls, pos); exit: return return_value; @@ -714,4 +733,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=8412b10c04259bb8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=da047f54b16cb309 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 84b58db6c7a702..9550c8728c251e 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -87,15 +87,19 @@ PyDoc_STRVAR(_io_BytesIO_getbuffer__doc__, "Get a read-write view over the contents of the BytesIO object."); #define _IO_BYTESIO_GETBUFFER_METHODDEF \ - {"getbuffer", (PyCFunction)_io_BytesIO_getbuffer, METH_NOARGS, _io_BytesIO_getbuffer__doc__}, + {"getbuffer", _PyCFunction_CAST(_io_BytesIO_getbuffer), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_BytesIO_getbuffer__doc__}, static PyObject * -_io_BytesIO_getbuffer_impl(bytesio *self); +_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls); static PyObject * -_io_BytesIO_getbuffer(bytesio *self, PyObject *Py_UNUSED(ignored)) +_io_BytesIO_getbuffer(bytesio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io_BytesIO_getbuffer_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments"); + return NULL; + } + return _io_BytesIO_getbuffer_impl(self, cls); } PyDoc_STRVAR(_io_BytesIO_getvalue__doc__, @@ -534,4 +538,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=a44770efbaeb80dd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=098584d485420b65 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index b6e9bd5b65a029..33a37a389d223d 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -18,15 +18,19 @@ PyDoc_STRVAR(_io_FileIO_close__doc__, "called more than once without error."); #define _IO_FILEIO_CLOSE_METHODDEF \ - {"close", (PyCFunction)_io_FileIO_close, METH_NOARGS, _io_FileIO_close__doc__}, + {"close", _PyCFunction_CAST(_io_FileIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_close__doc__}, static PyObject * -_io_FileIO_close_impl(fileio *self); +_io_FileIO_close_impl(fileio *self, PyTypeObject *cls); static PyObject * -_io_FileIO_close(fileio *self, PyObject *Py_UNUSED(ignored)) +_io_FileIO_close(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io_FileIO_close_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } + return _io_FileIO_close_impl(self, cls); } PyDoc_STRVAR(_io_FileIO___init____doc__, @@ -211,27 +215,45 @@ PyDoc_STRVAR(_io_FileIO_readinto__doc__, "Same as RawIOBase.readinto()."); #define _IO_FILEIO_READINTO_METHODDEF \ - {"readinto", (PyCFunction)_io_FileIO_readinto, METH_O, _io_FileIO_readinto__doc__}, + {"readinto", _PyCFunction_CAST(_io_FileIO_readinto), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_readinto__doc__}, static PyObject * -_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer); +_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer); static PyObject * -_io_FileIO_readinto(fileio *self, PyObject *arg) +_io_FileIO_readinto(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "readinto", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer buffer = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &buffer, PyBUF_WRITABLE) < 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &buffer, PyBUF_WRITABLE) < 0) { PyErr_Clear(); - _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); goto exit; } if (!PyBuffer_IsContiguous(&buffer, 'C')) { - _PyArg_BadArgument("readinto", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("readinto", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io_FileIO_readinto_impl(self, &buffer); + return_value = _io_FileIO_readinto_impl(self, cls, &buffer); exit: /* Cleanup for buffer */ @@ -274,28 +296,43 @@ PyDoc_STRVAR(_io_FileIO_read__doc__, "Return an empty bytes object at EOF."); #define _IO_FILEIO_READ_METHODDEF \ - {"read", _PyCFunction_CAST(_io_FileIO_read), METH_FASTCALL, _io_FileIO_read__doc__}, + {"read", _PyCFunction_CAST(_io_FileIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_read__doc__}, static PyObject * -_io_FileIO_read_impl(fileio *self, Py_ssize_t size); +_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size); static PyObject * -_io_FileIO_read(fileio *self, PyObject *const *args, Py_ssize_t nargs) +_io_FileIO_read(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_ssize_t size = -1; - if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { goto exit; } -skip_optional: - return_value = _io_FileIO_read_impl(self, size); +skip_optional_posonly: + return_value = _io_FileIO_read_impl(self, cls, size); exit: return return_value; @@ -312,25 +349,43 @@ PyDoc_STRVAR(_io_FileIO_write__doc__, "returns None if the write would block."); #define _IO_FILEIO_WRITE_METHODDEF \ - {"write", (PyCFunction)_io_FileIO_write, METH_O, _io_FileIO_write__doc__}, + {"write", _PyCFunction_CAST(_io_FileIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_write__doc__}, static PyObject * -_io_FileIO_write_impl(fileio *self, Py_buffer *b); +_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b); static PyObject * -_io_FileIO_write(fileio *self, PyObject *arg) +_io_FileIO_write(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer b = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&b, 'C')) { - _PyArg_BadArgument("write", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("write", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io_FileIO_write_impl(self, &b); + return_value = _io_FileIO_write_impl(self, cls, &b); exit: /* Cleanup for b */ @@ -418,26 +473,41 @@ PyDoc_STRVAR(_io_FileIO_truncate__doc__, "The current file position is changed to the value of size."); #define _IO_FILEIO_TRUNCATE_METHODDEF \ - {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_FASTCALL, _io_FileIO_truncate__doc__}, + {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_truncate__doc__}, static PyObject * -_io_FileIO_truncate_impl(fileio *self, PyObject *posobj); +_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj); static PyObject * -_io_FileIO_truncate(fileio *self, PyObject *const *args, Py_ssize_t nargs) +_io_FileIO_truncate(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "truncate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyObject *posobj = Py_None; - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } posobj = args[0]; -skip_optional: - return_value = _io_FileIO_truncate_impl(self, posobj); +skip_optional_posonly: + return_value = _io_FileIO_truncate_impl(self, cls, posobj); exit: return return_value; @@ -466,4 +536,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=27f883807a6c29ae input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bef47b31b644996a input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 01c035dad2641e..d3d537f6a1a0ef 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -136,15 +136,19 @@ PyDoc_STRVAR(_io__IOBase_fileno__doc__, "OSError is raised if the IO object does not use a file descriptor."); #define _IO__IOBASE_FILENO_METHODDEF \ - {"fileno", (PyCFunction)_io__IOBase_fileno, METH_NOARGS, _io__IOBase_fileno__doc__}, + {"fileno", _PyCFunction_CAST(_io__IOBase_fileno), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_fileno__doc__}, static PyObject * -_io__IOBase_fileno_impl(PyObject *self); +_io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_io__IOBase_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) +_io__IOBase_fileno(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__IOBase_fileno_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "fileno() takes no arguments"); + return NULL; + } + return _io__IOBase_fileno_impl(self, cls); } PyDoc_STRVAR(_io__IOBase_isatty__doc__, @@ -316,4 +320,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=b7246a2087eb966b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=98f212f95ac26d74 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h index df834dbde40f5b..d5544a3cd5b077 100644 --- a/Modules/_io/clinic/winconsoleio.c.h +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -20,15 +20,19 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__, "close() may be called more than once without error."); #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \ - {"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__}, + {"close", _PyCFunction_CAST(_io__WindowsConsoleIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_close__doc__}, static PyObject * -_io__WindowsConsoleIO_close_impl(winconsoleio *self); +_io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls); static PyObject * -_io__WindowsConsoleIO_close(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +_io__WindowsConsoleIO_close(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__WindowsConsoleIO_close_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } + return _io__WindowsConsoleIO_close_impl(self, cls); } #endif /* defined(MS_WINDOWS) */ @@ -278,28 +282,44 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_read__doc__, "Return an empty bytes object at EOF."); #define _IO__WINDOWSCONSOLEIO_READ_METHODDEF \ - {"read", _PyCFunction_CAST(_io__WindowsConsoleIO_read), METH_FASTCALL, _io__WindowsConsoleIO_read__doc__}, + {"read", _PyCFunction_CAST(_io__WindowsConsoleIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_read__doc__}, static PyObject * -_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size); +_io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, + Py_ssize_t size); static PyObject * -_io__WindowsConsoleIO_read(winconsoleio *self, PyObject *const *args, Py_ssize_t nargs) +_io__WindowsConsoleIO_read(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_ssize_t size = -1; - if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { goto exit; } -skip_optional: - return_value = _io__WindowsConsoleIO_read_impl(self, size); +skip_optional_posonly: + return_value = _io__WindowsConsoleIO_read_impl(self, cls, size); exit: return return_value; @@ -319,25 +339,44 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_write__doc__, "The number of bytes actually written is returned."); #define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF \ - {"write", (PyCFunction)_io__WindowsConsoleIO_write, METH_O, _io__WindowsConsoleIO_write__doc__}, + {"write", _PyCFunction_CAST(_io__WindowsConsoleIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_write__doc__}, static PyObject * -_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b); +_io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *b); static PyObject * -_io__WindowsConsoleIO_write(winconsoleio *self, PyObject *arg) +_io__WindowsConsoleIO_write(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer b = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&b, 'C')) { - _PyArg_BadArgument("write", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("write", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io__WindowsConsoleIO_write_impl(self, &b); + return_value = _io__WindowsConsoleIO_write_impl(self, cls, &b); exit: /* Cleanup for b */ @@ -407,4 +446,4 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ -/*[clinic end generated code: output=4920e9068e0cf08a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0bee002cc60d86d0 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 15b2a9fe5639b5..73987e0250ad08 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -129,6 +129,9 @@ internal_close(fileio *self) /*[clinic input] _io.FileIO.close + cls: defining_class + / + Close the file. A closed file cannot be used for further I/O operations. close() may be @@ -136,14 +139,14 @@ called more than once without error. [clinic start generated code]*/ static PyObject * -_io_FileIO_close_impl(fileio *self) -/*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/ +_io_FileIO_close_impl(fileio *self, PyTypeObject *cls) +/*[clinic end generated code: output=c30cbe9d1f23ca58 input=70da49e63db7c64d]*/ { PyObject *res; PyObject *exc, *val, *tb; int rc; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject *)self); if (!self->closefd) { @@ -242,7 +245,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int fstat_result; int async_err = 0; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); assert(PyFileIO_Check(state, self)); if (self->fd >= 0) { if (self->closefd) { @@ -539,12 +542,9 @@ err_closed(void) } static PyObject * -err_mode(const char *action) +err_mode(_PyIO_State *state, const char *action) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_Format(state->unsupported_operation, - "File not open for %s", action); + PyErr_Format(state->unsupported_operation, "File not open for %s", action); return NULL; } @@ -621,6 +621,7 @@ _io_FileIO_seekable_impl(fileio *self) /*[clinic input] _io.FileIO.readinto + cls: defining_class buffer: Py_buffer(accept={rwbuffer}) / @@ -628,16 +629,18 @@ Same as RawIOBase.readinto(). [clinic start generated code]*/ static PyObject * -_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) -/*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/ +_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer) +/*[clinic end generated code: output=97f0f3d69534db34 input=fd20323e18ce1ec8]*/ { Py_ssize_t n; int err; if (self->fd < 0) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } n = _Py_read(self->fd, buffer->buf, buffer->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ @@ -774,6 +777,7 @@ _io_FileIO_readall_impl(fileio *self) /*[clinic input] _io.FileIO.read + cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -785,8 +789,8 @@ Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * -_io_FileIO_read_impl(fileio *self, Py_ssize_t size) -/*[clinic end generated code: output=42528d39dd0ca641 input=bec9a2c704ddcbc9]*/ +_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) +/*[clinic end generated code: output=bbd749c7c224143e input=f613d2057e4a1918]*/ { char *ptr; Py_ssize_t n; @@ -794,8 +798,10 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size) if (self->fd < 0) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } if (size < 0) return _io_FileIO_readall_impl(self); @@ -833,6 +839,7 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size) /*[clinic input] _io.FileIO.write + cls: defining_class b: Py_buffer / @@ -844,16 +851,18 @@ returns None if the write would block. [clinic start generated code]*/ static PyObject * -_io_FileIO_write_impl(fileio *self, Py_buffer *b) -/*[clinic end generated code: output=b4059db3d363a2f7 input=6e7908b36f0ce74f]*/ +_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b) +/*[clinic end generated code: output=927e25be80f3b77b input=2776314f043088f5]*/ { Py_ssize_t n; int err; if (self->fd < 0) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "writing"); + } n = _Py_write(self->fd, b->buf, b->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ @@ -984,6 +993,7 @@ _io_FileIO_tell_impl(fileio *self) #ifdef HAVE_FTRUNCATE /*[clinic input] _io.FileIO.truncate + cls: defining_class size as posobj: object = None / @@ -994,8 +1004,8 @@ The current file position is changed to the value of size. [clinic start generated code]*/ static PyObject * -_io_FileIO_truncate_impl(fileio *self, PyObject *posobj) -/*[clinic end generated code: output=e49ca7a916c176fa input=b0ac133939823875]*/ +_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj) +/*[clinic end generated code: output=d936732a49e8d5a2 input=c367fb45d6bb2c18]*/ { Py_off_t pos; int ret; @@ -1004,8 +1014,10 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) fd = self->fd; if (fd < 0) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "writing"); + } if (posobj == Py_None) { /* Get the current position. */ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 98ee3d8c39bd1c..de79f6c5b545d6 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -71,11 +71,9 @@ PyDoc_STRVAR(iobase_doc, /* Internal methods */ static PyObject * -iobase_unsupported(const char *message) +iobase_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -97,7 +95,8 @@ PyDoc_STRVAR(iobase_seek_doc, static PyObject * iobase_seek(PyObject *self, PyObject *args) { - return iobase_unsupported("seek"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return iobase_unsupported(state, "seek"); } /*[clinic input] @@ -122,7 +121,8 @@ PyDoc_STRVAR(iobase_truncate_doc, static PyObject * iobase_truncate(PyObject *self, PyObject *args) { - return iobase_unsupported("truncate"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return iobase_unsupported(state, "truncate"); } static int @@ -384,7 +384,8 @@ _PyIOBase_check_seekable(PyObject *self, PyObject *args) return NULL; if (res != Py_True) { Py_CLEAR(res); - iobase_unsupported("File or stream is not seekable."); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + iobase_unsupported(state, "File or stream is not seekable."); return NULL; } if (args == Py_True) { @@ -417,7 +418,8 @@ _PyIOBase_check_readable(PyObject *self, PyObject *args) return NULL; if (res != Py_True) { Py_CLEAR(res); - iobase_unsupported("File or stream is not readable."); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + iobase_unsupported(state, "File or stream is not readable."); return NULL; } if (args == Py_True) { @@ -450,7 +452,8 @@ _PyIOBase_check_writable(PyObject *self, PyObject *args) return NULL; if (res != Py_True) { Py_CLEAR(res); - iobase_unsupported("File or stream is not writable."); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + iobase_unsupported(state, "File or stream is not writable."); return NULL; } if (args == Py_True) { @@ -483,16 +486,20 @@ iobase_exit(PyObject *self, PyObject *args) /*[clinic input] _io._IOBase.fileno + cls: defining_class + / + Returns underlying file descriptor if one exists. OSError is raised if the IO object does not use a file descriptor. [clinic start generated code]*/ static PyObject * -_io__IOBase_fileno_impl(PyObject *self) -/*[clinic end generated code: output=7cc0973f0f5f3b73 input=4e37028947dc1cc8]*/ +_io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=7caaa32a6f4ada3d input=9e960cc21e8889a3]*/ { - return iobase_unsupported("fileno"); + _PyIO_State *state = get_io_state_by_cls(cls); + return iobase_unsupported(state, "fileno"); } /*[clinic input] @@ -789,7 +796,7 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines) Py_RETURN_NONE; } -#define clinic_state() (IO_STATE()) +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/iobase.c.h" #undef clinic_state diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index e0f3b6d8d26804..1b4a0120a4c02f 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -401,7 +401,7 @@ stringio_iternext(stringio *self) CHECK_CLOSED(self); ENSURE_REALIZED(self); - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); if (Py_IS_TYPE(self, state->PyStringIO_Type)) { /* Skip method call overhead for speed */ line = _stringio_readline(self, -1); @@ -717,7 +717,7 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, } if (self->readuniversal) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->decoder = PyObject_CallFunctionObjArgs( (PyObject *)state->PyIncrementalNewlineDecoder_Type, Py_None, self->readtranslate ? Py_True : Py_False, NULL); @@ -969,7 +969,7 @@ stringio_newlines(stringio *self, void *context) return PyObject_GetAttr(self->decoder, &_Py_ID(newlines)); } -#define clinic_state() (IO_STATE()) +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/stringio.c.h" #undef clinic_state diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 1b0a310fc6191c..b4c74fa8e7ade7 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -34,11 +34,9 @@ PyDoc_STRVAR(textiobase_doc, ); static PyObject * -_unsupported(const char *message) +_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -52,7 +50,8 @@ PyDoc_STRVAR(textiobase_detach_doc, static PyObject * textiobase_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _unsupported("detach"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return _unsupported(state, "detach"); } PyDoc_STRVAR(textiobase_read_doc, @@ -65,7 +64,8 @@ PyDoc_STRVAR(textiobase_read_doc, static PyObject * textiobase_read(PyObject *self, PyObject *args) { - return _unsupported("read"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return _unsupported(state, "read"); } PyDoc_STRVAR(textiobase_readline_doc, @@ -77,7 +77,8 @@ PyDoc_STRVAR(textiobase_readline_doc, static PyObject * textiobase_readline(PyObject *self, PyObject *args) { - return _unsupported("readline"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return _unsupported(state, "readline"); } PyDoc_STRVAR(textiobase_write_doc, @@ -89,7 +90,8 @@ PyDoc_STRVAR(textiobase_write_doc, static PyObject * textiobase_write(PyObject *self, PyObject *args) { - return _unsupported("write"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return _unsupported(state, "write"); } PyDoc_STRVAR(textiobase_encoding_doc, @@ -871,7 +873,7 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, return -1; if (self->readuniversal) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = self->state; PyObject *incrementalDecoder = PyObject_CallFunctionObjArgs( (PyObject *)state->PyIncrementalNewlineDecoder_Type, self->decoder, self->readtranslate ? Py_True : Py_False, NULL); @@ -888,7 +890,7 @@ _textiowrapper_decode(PyObject *decoder, PyObject *bytes, int eof) { PyObject *chars; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(decoder)); if (Py_IS_TYPE(decoder, state->PyIncrementalNewlineDecoder_Type)) chars = _PyIncrementalNewlineDecoder_decode(decoder, bytes, eof); else @@ -1178,7 +1180,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, /* Finished sorting out the codec details */ Py_CLEAR(codec_info); - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); if (Py_IS_TYPE(buffer, state->PyBufferedReader_Type) || Py_IS_TYPE(buffer, state->PyBufferedWriter_Type) || Py_IS_TYPE(buffer, state->PyBufferedRandom_Type)) @@ -1328,7 +1330,8 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding, /* Check if something is in the read buffer */ if (self->decoded_chars != NULL) { if (encoding != Py_None || errors != Py_None || newline_obj != NULL) { - _unsupported("It is not possible to set the encoding or newline " + _unsupported(self->state, + "It is not possible to set the encoding or newline " "of stream after the first read"); return NULL; } @@ -1596,7 +1599,7 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) CHECK_CLOSED(self); if (self->encoder == NULL) - return _unsupported("not writable"); + return _unsupported(self->state, "not writable"); Py_INCREF(text); @@ -1777,7 +1780,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) */ if (self->decoder == NULL) { - _unsupported("not readable"); + _unsupported(self->state, "not readable"); return -1; } @@ -1902,7 +1905,7 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) CHECK_CLOSED(self); if (self->decoder == NULL) - return _unsupported("not readable"); + return _unsupported(self->state, "not readable"); if (_textiowrapper_writeflush(self) < 0) return NULL; @@ -2433,7 +2436,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) Py_INCREF(cookieObj); if (!self->seekable) { - _unsupported("underlying stream is not seekable"); + _unsupported(self->state, "underlying stream is not seekable"); goto fail; } @@ -2447,7 +2450,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) goto fail; if (cmp == 0) { - _unsupported("can't do nonzero cur-relative seeks"); + _unsupported(self->state, "can't do nonzero cur-relative seeks"); goto fail; } @@ -2467,7 +2470,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) goto fail; if (cmp == 0) { - _unsupported("can't do nonzero end-relative seeks"); + _unsupported(self->state, "can't do nonzero end-relative seeks"); goto fail; } @@ -2630,7 +2633,7 @@ _io_TextIOWrapper_tell_impl(textio *self) CHECK_CLOSED(self); if (!self->seekable) { - _unsupported("underlying stream is not seekable"); + _unsupported(self->state, "underlying stream is not seekable"); goto fail; } if (!self->telling) { @@ -3062,8 +3065,7 @@ textiowrapper_iternext(textio *self) CHECK_ATTACHED(self); self->telling = 0; - _PyIO_State *state = IO_STATE(); - if (Py_IS_TYPE(self, state->PyTextIOWrapper_Type)) { + if (Py_IS_TYPE(self, self->state->PyTextIOWrapper_Type)) { /* Skip method call overhead for speed */ line = _textiowrapper_readline(self, -1); } @@ -3155,7 +3157,7 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) return 0; } -#define clinic_state() (IO_STATE()) +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/textio.c.h" #undef clinic_state diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 6925f088ab7fba..4e4343a63480a8 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -181,6 +181,9 @@ internal_close(winconsoleio *self) /*[clinic input] _io._WindowsConsoleIO.close + cls: defining_class + / + Close the console object. A closed console object cannot be used for further I/O operations. @@ -188,14 +191,14 @@ close() may be called more than once without error. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_close_impl(winconsoleio *self) -/*[clinic end generated code: output=27ef95b66c29057b input=68c4e5754f8136c2]*/ +_io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls) +/*[clinic end generated code: output=e50c1808c063e1e2 input=f200f26059fb2ecf]*/ { PyObject *res; PyObject *exc, *val, *tb; int rc; - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject*)self); if (!self->closefd) { @@ -449,12 +452,10 @@ err_closed(void) } static PyObject * -err_mode(const char *action) +err_mode(_PyIO_State *state, const char *action) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_Format(state->unsupported_operation, - "Console buffer does not support %s", action); + PyErr_Format(state->unsupported_operation, + "Console buffer does not support %s", action); return NULL; } @@ -639,7 +640,8 @@ readinto(winconsoleio *self, char *buf, Py_ssize_t len) return -1; } if (!self->readable) { - err_mode("reading"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + err_mode(state, "reading"); return -1; } if (len == 0) @@ -893,6 +895,7 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) /*[clinic input] _io._WindowsConsoleIO.read + cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -904,16 +907,19 @@ Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) -/*[clinic end generated code: output=57df68af9f4b22d0 input=8bc73bc15d0fa072]*/ +_io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, + Py_ssize_t size) +/*[clinic end generated code: output=7e569a586537c0ae input=a14570a5da273365]*/ { PyObject *bytes; Py_ssize_t bytes_size; if (self->fd == -1) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } if (size < 0) return _io__WindowsConsoleIO_readall_impl(self); @@ -944,6 +950,7 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) /*[clinic input] _io._WindowsConsoleIO.write + cls: defining_class b: Py_buffer / @@ -954,8 +961,9 @@ The number of bytes actually written is returned. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b) -/*[clinic end generated code: output=775bdb16fbf9137b input=be35fb624f97c941]*/ +_io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *b) +/*[clinic end generated code: output=e8019f480243cb29 input=10ac37c19339dfbe]*/ { BOOL res = TRUE; wchar_t *wbuf; @@ -964,8 +972,10 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b) if (self->fd == -1) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "writing"); + } handle = _Py_get_osfhandle(self->fd); if (handle == INVALID_HANDLE_VALUE) @@ -1078,7 +1088,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 From 4e641987eab2f7c196e60a3a42840a6e42424fc0 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Mon, 20 Feb 2023 22:19:20 +0530 Subject: [PATCH 18/54] Fix state assignment --- Modules/_io/textio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b4c74fa8e7ade7..9e74f892990a4f 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1169,6 +1169,8 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, self->buffer = Py_NewRef(buffer); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + self->state = state; /* Build the decoder object */ if (_textiowrapper_set_decoder(self, codec_info, PyUnicode_AsUTF8(errors)) != 0) goto error; @@ -1180,7 +1182,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, /* Finished sorting out the codec details */ Py_CLEAR(codec_info); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); if (Py_IS_TYPE(buffer, state->PyBufferedReader_Type) || Py_IS_TYPE(buffer, state->PyBufferedWriter_Type) || Py_IS_TYPE(buffer, state->PyBufferedRandom_Type)) @@ -1216,8 +1217,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, if (_textiowrapper_fix_encoder_state(self) < 0) { goto error; } - - self->state = state; + self->ok = 1; return 0; From a51823a6ece769f9c3af757b270f34755b401968 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 20 Feb 2023 23:05:51 +0100 Subject: [PATCH 19/54] Experimental: add explicit finalizers to all types Also remove calls to _PyIOBase_finalize from dealloc funcs --- Modules/_io/_iomodule.h | 1 + Modules/_io/bufferedio.c | 7 +++++-- Modules/_io/bytesio.c | 2 ++ Modules/_io/fileio.c | 3 +-- Modules/_io/iobase.c | 31 +------------------------------ Modules/_io/stringio.c | 1 + Modules/_io/textio.c | 7 ++++--- Modules/_io/winconsoleio.c | 3 +-- 8 files changed, 16 insertions(+), 39 deletions(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index e90bfd9e4d7ee1..2cc5e90a712455 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -135,6 +135,7 @@ extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err); /* IO module structure */ extern PyModuleDef _PyIO_Module; +extern void iobase_finalize(PyObject *); typedef struct { PyObject *locale_module; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 36babd3055100d..d973de437804b1 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -373,8 +373,6 @@ buffered_dealloc(buffered *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; - if (_PyIOBase_finalize((PyObject *) self) < 0) - return; _PyObject_GC_UNTRACK(self); self->ok = 0; if (self->weakreflist != NULL) @@ -2362,6 +2360,7 @@ static PyType_Slot bufferediobase_slots[] = { {Py_tp_doc, (void *)bufferediobase_doc}, {Py_tp_methods, bufferediobase_methods}, {Py_tp_traverse, bufferediobase_traverse}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2423,6 +2422,7 @@ static PyType_Slot bufferedreader_slots[] = { {Py_tp_members, bufferedreader_members}, {Py_tp_getset, bufferedreader_getset}, {Py_tp_init, _io_BufferedReader___init__}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2479,6 +2479,7 @@ static PyType_Slot bufferedwriter_slots[] = { {Py_tp_members, bufferedwriter_members}, {Py_tp_getset, bufferedwriter_getset}, {Py_tp_init, _io_BufferedWriter___init__}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2529,6 +2530,7 @@ static PyType_Slot bufferedrwpair_slots[] = { {Py_tp_members, bufferedrwpair_members}, {Py_tp_getset, bufferedrwpair_getset}, {Py_tp_init, _io_BufferedRWPair___init__}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2595,6 +2597,7 @@ static PyType_Slot bufferedrandom_slots[] = { {Py_tp_members, bufferedrandom_members}, {Py_tp_getset, bufferedrandom_getset}, {Py_tp_init, _io_BufferedRandom___init__}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 6a7d9fad8a2a83..f2824615babfe0 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1043,6 +1043,7 @@ static PyType_Slot bytesio_slots[] = { {Py_tp_getset, bytesio_getsetlist}, {Py_tp_init, _io_BytesIO___init__}, {Py_tp_new, bytesio_new}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -1112,6 +1113,7 @@ bytesiobuf_dealloc(bytesiobuf *self) static PyType_Slot bytesiobuf_slots[] = { {Py_tp_dealloc, bytesiobuf_dealloc}, {Py_tp_traverse, bytesiobuf_traverse}, + {Py_tp_finalize, iobase_finalize}, // Buffer protocol {Py_bf_getbuffer, bytesiobuf_getbuffer}, diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index b0a5d42c0d9627..fdf9693d1de592 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -526,8 +526,6 @@ fileio_dealloc(fileio *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; - if (_PyIOBase_finalize((PyObject *) self) < 0) - return; _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -1211,6 +1209,7 @@ static PyType_Slot fileio_slots[] = { {Py_tp_getset, fileio_getsetlist}, {Py_tp_init, _io_FileIO___init__}, {Py_tp_new, fileio_new}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index de79f6c5b545d6..edb111a0b5730f 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -248,7 +248,7 @@ _io__IOBase_close_impl(PyObject *self) /* Finalization and garbage collection support */ -static void +void iobase_finalize(PyObject *self) { PyObject *res; @@ -300,22 +300,6 @@ iobase_finalize(PyObject *self) PyErr_Restore(error_type, error_value, error_traceback); } -int -_PyIOBase_finalize(PyObject *self) -{ - int is_zombie; - - /* If _PyIOBase_finalize() is called from a destructor, we need to - resurrect the object as calling close() can invoke arbitrary code. */ - is_zombie = (Py_REFCNT(self) == 0); - if (is_zombie) - return PyObject_CallFinalizerFromDealloc(self); - else { - PyObject_CallFinalizer(self); - return 0; - } -} - static int iobase_traverse(iobase *self, visitproc visit, void *arg) { @@ -336,19 +320,6 @@ iobase_clear(iobase *self) static void iobase_dealloc(iobase *self) { - /* NOTE: since IOBaseObject has its own dict, Python-defined attributes - are still available here for close() to use. - However, if the derived class declares a __slots__, those slots are - already gone. - */ - if (_PyIOBase_finalize((PyObject *) self) < 0) { - /* When called from a heap type's dealloc, the type will be - decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ - if (_PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) { - Py_INCREF(Py_TYPE(self)); - } - return; - } PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 1cd8e01b3ed466..5b0a4b82360817 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1022,6 +1022,7 @@ static PyType_Slot stringio_slots[] = { {Py_tp_getset, stringio_getset}, {Py_tp_init, _io_StringIO___init__}, {Py_tp_new, stringio_new}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 9e74f892990a4f..b147cbb0e08451 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -169,6 +169,7 @@ static PyType_Slot textiobase_slots[] = { {Py_tp_methods, textiobase_methods}, {Py_tp_getset, textiobase_getset}, {Py_tp_traverse, textiobase_traverse}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -873,7 +874,7 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, return -1; if (self->readuniversal) { - _PyIO_State *state = self->state; + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); PyObject *incrementalDecoder = PyObject_CallFunctionObjArgs( (PyObject *)state->PyIncrementalNewlineDecoder_Type, self->decoder, self->readtranslate ? Py_True : Py_False, NULL); @@ -1397,8 +1398,6 @@ textiowrapper_dealloc(textio *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; - if (_PyIOBase_finalize((PyObject *) self) < 0) - return; self->ok = 0; _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) @@ -3182,6 +3181,7 @@ static PyType_Slot nldecoder_slots[] = { {Py_tp_traverse, incrementalnewlinedecoder_traverse}, {Py_tp_clear, incrementalnewlinedecoder_clear}, {Py_tp_init, _io_IncrementalNewlineDecoder___init__}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -3249,6 +3249,7 @@ PyType_Slot textiowrapper_slots[] = { {Py_tp_members, textiowrapper_members}, {Py_tp_getset, textiowrapper_getset}, {Py_tp_init, _io_TextIOWrapper___init__}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 4e4343a63480a8..a63902b58d4759 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -434,8 +434,6 @@ winconsoleio_dealloc(winconsoleio *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; - if (_PyIOBase_finalize((PyObject *) self) < 0) - return; _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -1153,6 +1151,7 @@ static PyType_Slot winconsoleio_slots[] = { {Py_tp_getset, winconsoleio_getsetlist}, {Py_tp_init, _io__WindowsConsoleIO___init__}, {Py_tp_new, winconsoleio_new}, + {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; From 0cdd1eae3d33dc0fcf2ee25c395a81b262876737 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 20 Feb 2023 23:46:52 +0100 Subject: [PATCH 20/54] Fix check readable/writable/seekable methods --- .../pycore_global_objects_fini_generated.h | 3 + Include/internal/pycore_global_strings.h | 3 + .../internal/pycore_runtime_init_generated.h | 3 + .../internal/pycore_unicodeobject_generated.h | 6 + Modules/_io/_iomodule.h | 13 +- Modules/_io/bufferedio.c | 23 +-- Modules/_io/clinic/iobase.c.h | 134 +++++++++++++++++- Modules/_io/iobase.c | 59 ++++++-- 8 files changed, 217 insertions(+), 27 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index dc5cd58d853534..829f7c44a94b37 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -742,6 +742,9 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_asyncio_future_blocking)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_blksize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_bootstrap)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_checkReadable)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_checkSeekable)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_checkWritable)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_check_retval_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_dealloc_warn)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_feature_version)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 8b23aa15479301..2e16c9edfbbdac 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -228,6 +228,9 @@ struct _Py_global_strings { STRUCT_FOR_ID(_asyncio_future_blocking) STRUCT_FOR_ID(_blksize) STRUCT_FOR_ID(_bootstrap) + STRUCT_FOR_ID(_checkReadable) + STRUCT_FOR_ID(_checkSeekable) + STRUCT_FOR_ID(_checkWritable) STRUCT_FOR_ID(_check_retval_) STRUCT_FOR_ID(_dealloc_warn) STRUCT_FOR_ID(_feature_version) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 471efadb13bb4f..3fc14481c95c44 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -734,6 +734,9 @@ extern "C" { INIT_ID(_asyncio_future_blocking), \ INIT_ID(_blksize), \ INIT_ID(_bootstrap), \ + INIT_ID(_checkReadable), \ + INIT_ID(_checkSeekable), \ + INIT_ID(_checkWritable), \ INIT_ID(_check_retval_), \ INIT_ID(_dealloc_warn), \ INIT_ID(_feature_version), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index b47d240e492ff9..792b7317e09b38 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -362,6 +362,12 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(_bootstrap); PyUnicode_InternInPlace(&string); + string = &_Py_ID(_checkReadable); + PyUnicode_InternInPlace(&string); + string = &_Py_ID(_checkSeekable); + PyUnicode_InternInPlace(&string); + string = &_Py_ID(_checkWritable); + PyUnicode_InternInPlace(&string); string = &_Py_ID(_check_retval_); PyUnicode_InternInPlace(&string); string = &_Py_ID(_dealloc_warn); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 2cc5e90a712455..dd668ceeff69ad 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -26,14 +26,19 @@ extern PyType_Spec textiowrapper_spec; extern PyType_Spec winconsoleio_spec; #endif +#define _CHECK(op, id) (PyObject_CallMethodOneArg(op, id, Py_True)) +#define CHECK_READABLE(op) (_CHECK(op, &_Py_ID(_checkReadable))) +#define CHECK_SEEKABLE(op) (_CHECK(op, &_Py_ID(_checkSeekable))) +#define CHECK_WRITABLE(op) (_CHECK(op, &_Py_ID(_checkWritable))) + /* These functions are used as METH_NOARGS methods, are normally called * with args=NULL, and return a new reference. * BUT when args=Py_True is passed, they return a borrowed reference. */ -extern PyObject* _PyIOBase_check_readable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_writable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_seekable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); +extern PyObject *_PyIOBase_check_readable(PyObject *self, PyObject *args); +extern PyObject *_PyIOBase_check_writable(PyObject *self, PyObject *args); +extern PyObject *_PyIOBase_check_seekable(PyObject *self, PyObject *args); +extern PyObject *_PyIOBase_check_closed(PyObject *self, PyObject *args); /* Helper for finalization. This function will revive an object ready to be deallocated and try to diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index d973de437804b1..d79512cf869188 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1227,7 +1227,7 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) CHECK_CLOSED(self, "seek of closed file") - if (_PyIOBase_check_seekable(self->raw, Py_True) == NULL) + if (CHECK_SEEKABLE(self->raw) == NULL) return NULL; target = PyNumber_AsOff_t(targetobj, PyExc_ValueError); @@ -1426,8 +1426,9 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) + if (CHECK_READABLE(raw) == NULL) { return -1; + } Py_XSETREF(self->raw, Py_NewRef(raw)); self->buffer_size = buffer_size; @@ -1782,8 +1783,9 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) + if (CHECK_WRITABLE(raw) == NULL) { return -1; + } Py_INCREF(raw); Py_XSETREF(self->raw, raw); @@ -2101,10 +2103,12 @@ _io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, PyObject *writer, Py_ssize_t buffer_size) /*[clinic end generated code: output=327e73d1aee8f984 input=620d42d71f33a031]*/ { - if (_PyIOBase_check_readable(reader, Py_True) == NULL) + if (CHECK_READABLE(reader) == NULL) { return -1; - if (_PyIOBase_check_writable(writer, Py_True) == NULL) + } + if (CHECK_WRITABLE(writer) == NULL) { return -1; + } _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->reader = (buffered *) PyObject_CallFunction( @@ -2298,12 +2302,15 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_seekable(raw, Py_True) == NULL) + if (CHECK_SEEKABLE(raw) == NULL) { return -1; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) + } + if (CHECK_READABLE(raw) == NULL) { return -1; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) + } + if (CHECK_WRITABLE(raw) == NULL) { return -1; + } Py_INCREF(raw); Py_XSETREF(self->raw, raw); diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index d3d537f6a1a0ef..c9ff825338f3e7 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -87,6 +87,50 @@ _io__IOBase_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_seekable_impl(self); } +PyDoc_STRVAR(_io__IOBase__checkSeekable__doc__, +"_checkSeekable($self, /, *args)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKSEEKABLE_METHODDEF \ + {"_checkSeekable", _PyCFunction_CAST(_io__IOBase__checkSeekable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase__checkSeekable__doc__}, + +static PyObject * +_io__IOBase__checkSeekable_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__IOBase__checkSeekable(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_checkSeekable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__IOBase__checkSeekable_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(_io__IOBase_readable__doc__, "readable($self, /)\n" "--\n" @@ -107,6 +151,50 @@ _io__IOBase_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_readable_impl(self); } +PyDoc_STRVAR(_io__IOBase__checkReadable__doc__, +"_checkReadable($self, /, *args)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKREADABLE_METHODDEF \ + {"_checkReadable", _PyCFunction_CAST(_io__IOBase__checkReadable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase__checkReadable__doc__}, + +static PyObject * +_io__IOBase__checkReadable_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__IOBase__checkReadable(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_checkReadable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__IOBase__checkReadable_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(_io__IOBase_writable__doc__, "writable($self, /)\n" "--\n" @@ -127,6 +215,50 @@ _io__IOBase_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_writable_impl(self); } +PyDoc_STRVAR(_io__IOBase__checkWritable__doc__, +"_checkWritable($self, /, *args)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKWRITABLE_METHODDEF \ + {"_checkWritable", _PyCFunction_CAST(_io__IOBase__checkWritable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase__checkWritable__doc__}, + +static PyObject * +_io__IOBase__checkWritable_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__IOBase__checkWritable(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_checkWritable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__IOBase__checkWritable_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(_io__IOBase_fileno__doc__, "fileno($self, /)\n" "--\n" @@ -320,4 +452,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=98f212f95ac26d74 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cc302d8dc238cf37 input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index edb111a0b5730f..444c1dbbd7bdcb 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -347,15 +347,26 @@ _io__IOBase_seekable_impl(PyObject *self) Py_RETURN_FALSE; } -PyObject * -_PyIOBase_check_seekable(PyObject *self, PyObject *args) +/*[clinic input] +_io._IOBase._checkSeekable + + cls: defining_class + / + *args: object + +[clinic start generated code]*/ + +static PyObject * +_io__IOBase__checkSeekable_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=f9449595c526a9ed input=6cf1584801d4b564]*/ { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(seekable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); iobase_unsupported(state, "File or stream is not seekable."); return NULL; } @@ -380,16 +391,26 @@ _io__IOBase_readable_impl(PyObject *self) Py_RETURN_FALSE; } -/* May be called with any object */ -PyObject * -_PyIOBase_check_readable(PyObject *self, PyObject *args) +/*[clinic input] +_io._IOBase._checkReadable + + cls: defining_class + / + *args: object + +[clinic start generated code]*/ + +static PyObject * +_io__IOBase__checkReadable_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=2eefd0c6015d18d3 input=cb9e598f66479243]*/ { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(readable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); iobase_unsupported(state, "File or stream is not readable."); return NULL; } @@ -414,16 +435,26 @@ _io__IOBase_writable_impl(PyObject *self) Py_RETURN_FALSE; } -/* May be called with any object */ -PyObject * -_PyIOBase_check_writable(PyObject *self, PyObject *args) +/*[clinic input] +_io._IOBase._checkWritable + + cls: defining_class + / + *args: object + +[clinic start generated code]*/ + +static PyObject * +_io__IOBase__checkWritable_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=db0ec8af34f05a01 input=a385662e0b185943]*/ { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(writable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); iobase_unsupported(state, "File or stream is not writable."); return NULL; } @@ -783,9 +814,9 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_WRITABLE_METHODDEF {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, - {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS}, - {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS}, - {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS}, + _IO__IOBASE__CHECKSEEKABLE_METHODDEF + _IO__IOBASE__CHECKREADABLE_METHODDEF + _IO__IOBASE__CHECKWRITABLE_METHODDEF _IO__IOBASE_FILENO_METHODDEF _IO__IOBASE_ISATTY_METHODDEF From 3a1ed0bda6c41d1e2e16a63eae536d33783ae566 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 20 Feb 2023 23:50:43 +0100 Subject: [PATCH 21/54] Fix _textiowrapper_decode --- Modules/_io/textio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b147cbb0e08451..4a43c06136ba6e 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -887,11 +887,11 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, } static PyObject* -_textiowrapper_decode(PyObject *decoder, PyObject *bytes, int eof) +_textiowrapper_decode(_PyIO_State *state, PyObject *decoder, PyObject *bytes, + int eof) { PyObject *chars; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(decoder)); if (Py_IS_TYPE(decoder, state->PyIncrementalNewlineDecoder_Type)) chars = _PyIncrementalNewlineDecoder_decode(decoder, bytes, eof); else @@ -1846,7 +1846,8 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) nbytes = input_chunk_buf.len; eof = (nbytes == 0); - decoded_chars = _textiowrapper_decode(self->decoder, input_chunk, eof); + decoded_chars = _textiowrapper_decode(self->state, self->decoder, + input_chunk, eof); PyBuffer_Release(&input_chunk_buf); if (decoded_chars == NULL) goto fail; From 039b757170053597bbac3e5935d95e61157042ab Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 20 Feb 2023 23:59:32 +0100 Subject: [PATCH 22/54] Revert "Experimental: add explicit finalizers to all types" This reverts commit a51823a6ece769f9c3af757b270f34755b401968. --- Modules/_io/_iomodule.h | 1 - Modules/_io/bufferedio.c | 7 ++----- Modules/_io/bytesio.c | 2 -- Modules/_io/fileio.c | 3 ++- Modules/_io/iobase.c | 31 ++++++++++++++++++++++++++++++- Modules/_io/stringio.c | 1 - Modules/_io/textio.c | 7 +++---- Modules/_io/winconsoleio.c | 3 ++- 8 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index dd668ceeff69ad..e6addc12450d4c 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -140,7 +140,6 @@ extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err); /* IO module structure */ extern PyModuleDef _PyIO_Module; -extern void iobase_finalize(PyObject *); typedef struct { PyObject *locale_module; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index d79512cf869188..9a249634c6dfc7 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -373,6 +373,8 @@ buffered_dealloc(buffered *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) + return; _PyObject_GC_UNTRACK(self); self->ok = 0; if (self->weakreflist != NULL) @@ -2367,7 +2369,6 @@ static PyType_Slot bufferediobase_slots[] = { {Py_tp_doc, (void *)bufferediobase_doc}, {Py_tp_methods, bufferediobase_methods}, {Py_tp_traverse, bufferediobase_traverse}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2429,7 +2430,6 @@ static PyType_Slot bufferedreader_slots[] = { {Py_tp_members, bufferedreader_members}, {Py_tp_getset, bufferedreader_getset}, {Py_tp_init, _io_BufferedReader___init__}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2486,7 +2486,6 @@ static PyType_Slot bufferedwriter_slots[] = { {Py_tp_members, bufferedwriter_members}, {Py_tp_getset, bufferedwriter_getset}, {Py_tp_init, _io_BufferedWriter___init__}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2537,7 +2536,6 @@ static PyType_Slot bufferedrwpair_slots[] = { {Py_tp_members, bufferedrwpair_members}, {Py_tp_getset, bufferedrwpair_getset}, {Py_tp_init, _io_BufferedRWPair___init__}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -2604,7 +2602,6 @@ static PyType_Slot bufferedrandom_slots[] = { {Py_tp_members, bufferedrandom_members}, {Py_tp_getset, bufferedrandom_getset}, {Py_tp_init, _io_BufferedRandom___init__}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index f2824615babfe0..6a7d9fad8a2a83 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1043,7 +1043,6 @@ static PyType_Slot bytesio_slots[] = { {Py_tp_getset, bytesio_getsetlist}, {Py_tp_init, _io_BytesIO___init__}, {Py_tp_new, bytesio_new}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -1113,7 +1112,6 @@ bytesiobuf_dealloc(bytesiobuf *self) static PyType_Slot bytesiobuf_slots[] = { {Py_tp_dealloc, bytesiobuf_dealloc}, {Py_tp_traverse, bytesiobuf_traverse}, - {Py_tp_finalize, iobase_finalize}, // Buffer protocol {Py_bf_getbuffer, bytesiobuf_getbuffer}, diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index fdf9693d1de592..b0a5d42c0d9627 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -526,6 +526,8 @@ fileio_dealloc(fileio *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) + return; _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -1209,7 +1211,6 @@ static PyType_Slot fileio_slots[] = { {Py_tp_getset, fileio_getsetlist}, {Py_tp_init, _io_FileIO___init__}, {Py_tp_new, fileio_new}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 444c1dbbd7bdcb..febe4c412d9c70 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -248,7 +248,7 @@ _io__IOBase_close_impl(PyObject *self) /* Finalization and garbage collection support */ -void +static void iobase_finalize(PyObject *self) { PyObject *res; @@ -300,6 +300,22 @@ iobase_finalize(PyObject *self) PyErr_Restore(error_type, error_value, error_traceback); } +int +_PyIOBase_finalize(PyObject *self) +{ + int is_zombie; + + /* If _PyIOBase_finalize() is called from a destructor, we need to + resurrect the object as calling close() can invoke arbitrary code. */ + is_zombie = (Py_REFCNT(self) == 0); + if (is_zombie) + return PyObject_CallFinalizerFromDealloc(self); + else { + PyObject_CallFinalizer(self); + return 0; + } +} + static int iobase_traverse(iobase *self, visitproc visit, void *arg) { @@ -320,6 +336,19 @@ iobase_clear(iobase *self) static void iobase_dealloc(iobase *self) { + /* NOTE: since IOBaseObject has its own dict, Python-defined attributes + are still available here for close() to use. + However, if the derived class declares a __slots__, those slots are + already gone. + */ + if (_PyIOBase_finalize((PyObject *) self) < 0) { + /* When called from a heap type's dealloc, the type will be + decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ + if (_PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) { + Py_INCREF(Py_TYPE(self)); + } + return; + } PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 5b0a4b82360817..1cd8e01b3ed466 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1022,7 +1022,6 @@ static PyType_Slot stringio_slots[] = { {Py_tp_getset, stringio_getset}, {Py_tp_init, _io_StringIO___init__}, {Py_tp_new, stringio_new}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 4a43c06136ba6e..aaec54cc3f9766 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -169,7 +169,6 @@ static PyType_Slot textiobase_slots[] = { {Py_tp_methods, textiobase_methods}, {Py_tp_getset, textiobase_getset}, {Py_tp_traverse, textiobase_traverse}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -874,7 +873,7 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, return -1; if (self->readuniversal) { - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = self->state; PyObject *incrementalDecoder = PyObject_CallFunctionObjArgs( (PyObject *)state->PyIncrementalNewlineDecoder_Type, self->decoder, self->readtranslate ? Py_True : Py_False, NULL); @@ -1398,6 +1397,8 @@ textiowrapper_dealloc(textio *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) + return; self->ok = 0; _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) @@ -3182,7 +3183,6 @@ static PyType_Slot nldecoder_slots[] = { {Py_tp_traverse, incrementalnewlinedecoder_traverse}, {Py_tp_clear, incrementalnewlinedecoder_clear}, {Py_tp_init, _io_IncrementalNewlineDecoder___init__}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; @@ -3250,7 +3250,6 @@ PyType_Slot textiowrapper_slots[] = { {Py_tp_members, textiowrapper_members}, {Py_tp_getset, textiowrapper_getset}, {Py_tp_init, _io_TextIOWrapper___init__}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index a63902b58d4759..4e4343a63480a8 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -434,6 +434,8 @@ winconsoleio_dealloc(winconsoleio *self) { PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) + return; _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -1151,7 +1153,6 @@ static PyType_Slot winconsoleio_slots[] = { {Py_tp_getset, winconsoleio_getsetlist}, {Py_tp_init, _io__WindowsConsoleIO___init__}, {Py_tp_new, winconsoleio_new}, - {Py_tp_finalize, iobase_finalize}, {0, NULL}, }; From 17eb640c5406bca6396fce5e69d0eb50b1f100f6 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 00:05:37 +0100 Subject: [PATCH 23/54] Purge old exports --- Modules/_io/_iomodule.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index e6addc12450d4c..c07df4f2cd7668 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -31,13 +31,6 @@ extern PyType_Spec winconsoleio_spec; #define CHECK_SEEKABLE(op) (_CHECK(op, &_Py_ID(_checkSeekable))) #define CHECK_WRITABLE(op) (_CHECK(op, &_Py_ID(_checkWritable))) -/* These functions are used as METH_NOARGS methods, are normally called - * with args=NULL, and return a new reference. - * BUT when args=Py_True is passed, they return a borrowed reference. - */ -extern PyObject *_PyIOBase_check_readable(PyObject *self, PyObject *args); -extern PyObject *_PyIOBase_check_writable(PyObject *self, PyObject *args); -extern PyObject *_PyIOBase_check_seekable(PyObject *self, PyObject *args); extern PyObject *_PyIOBase_check_closed(PyObject *self, PyObject *args); /* Helper for finalization. From 00d5abb525e03e12cb7a2421104a14eddd1a79a2 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 12:11:42 +0100 Subject: [PATCH 24/54] Revert "Fix check readable/writable/seekable methods" This reverts commit 0cdd1eae3d33dc0fcf2ee25c395a81b262876737. --- .../pycore_global_objects_fini_generated.h | 3 - Include/internal/pycore_global_strings.h | 3 - .../internal/pycore_runtime_init_generated.h | 3 - .../internal/pycore_unicodeobject_generated.h | 6 - Modules/_io/_iomodule.h | 14 +- Modules/_io/bufferedio.c | 23 ++- Modules/_io/clinic/iobase.c.h | 134 +----------------- Modules/_io/iobase.c | 59 ++------ 8 files changed, 31 insertions(+), 214 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 829f7c44a94b37..dc5cd58d853534 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -742,9 +742,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_asyncio_future_blocking)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_blksize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_bootstrap)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_checkReadable)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_checkSeekable)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_checkWritable)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_check_retval_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_dealloc_warn)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_feature_version)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 2e16c9edfbbdac..8b23aa15479301 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -228,9 +228,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(_asyncio_future_blocking) STRUCT_FOR_ID(_blksize) STRUCT_FOR_ID(_bootstrap) - STRUCT_FOR_ID(_checkReadable) - STRUCT_FOR_ID(_checkSeekable) - STRUCT_FOR_ID(_checkWritable) STRUCT_FOR_ID(_check_retval_) STRUCT_FOR_ID(_dealloc_warn) STRUCT_FOR_ID(_feature_version) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 3fc14481c95c44..471efadb13bb4f 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -734,9 +734,6 @@ extern "C" { INIT_ID(_asyncio_future_blocking), \ INIT_ID(_blksize), \ INIT_ID(_bootstrap), \ - INIT_ID(_checkReadable), \ - INIT_ID(_checkSeekable), \ - INIT_ID(_checkWritable), \ INIT_ID(_check_retval_), \ INIT_ID(_dealloc_warn), \ INIT_ID(_feature_version), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 792b7317e09b38..b47d240e492ff9 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -362,12 +362,6 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(_bootstrap); PyUnicode_InternInPlace(&string); - string = &_Py_ID(_checkReadable); - PyUnicode_InternInPlace(&string); - string = &_Py_ID(_checkSeekable); - PyUnicode_InternInPlace(&string); - string = &_Py_ID(_checkWritable); - PyUnicode_InternInPlace(&string); string = &_Py_ID(_check_retval_); PyUnicode_InternInPlace(&string); string = &_Py_ID(_dealloc_warn); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index c07df4f2cd7668..e90bfd9e4d7ee1 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -26,12 +26,14 @@ extern PyType_Spec textiowrapper_spec; extern PyType_Spec winconsoleio_spec; #endif -#define _CHECK(op, id) (PyObject_CallMethodOneArg(op, id, Py_True)) -#define CHECK_READABLE(op) (_CHECK(op, &_Py_ID(_checkReadable))) -#define CHECK_SEEKABLE(op) (_CHECK(op, &_Py_ID(_checkSeekable))) -#define CHECK_WRITABLE(op) (_CHECK(op, &_Py_ID(_checkWritable))) - -extern PyObject *_PyIOBase_check_closed(PyObject *self, PyObject *args); +/* These functions are used as METH_NOARGS methods, are normally called + * with args=NULL, and return a new reference. + * BUT when args=Py_True is passed, they return a borrowed reference. + */ +extern PyObject* _PyIOBase_check_readable(PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_writable(PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_seekable(PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); /* Helper for finalization. This function will revive an object ready to be deallocated and try to diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 9a249634c6dfc7..36babd3055100d 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1229,7 +1229,7 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) CHECK_CLOSED(self, "seek of closed file") - if (CHECK_SEEKABLE(self->raw) == NULL) + if (_PyIOBase_check_seekable(self->raw, Py_True) == NULL) return NULL; target = PyNumber_AsOff_t(targetobj, PyExc_ValueError); @@ -1428,9 +1428,8 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (CHECK_READABLE(raw) == NULL) { + if (_PyIOBase_check_readable(raw, Py_True) == NULL) return -1; - } Py_XSETREF(self->raw, Py_NewRef(raw)); self->buffer_size = buffer_size; @@ -1785,9 +1784,8 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (CHECK_WRITABLE(raw) == NULL) { + if (_PyIOBase_check_writable(raw, Py_True) == NULL) return -1; - } Py_INCREF(raw); Py_XSETREF(self->raw, raw); @@ -2105,12 +2103,10 @@ _io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, PyObject *writer, Py_ssize_t buffer_size) /*[clinic end generated code: output=327e73d1aee8f984 input=620d42d71f33a031]*/ { - if (CHECK_READABLE(reader) == NULL) { + if (_PyIOBase_check_readable(reader, Py_True) == NULL) return -1; - } - if (CHECK_WRITABLE(writer) == NULL) { + if (_PyIOBase_check_writable(writer, Py_True) == NULL) return -1; - } _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->reader = (buffered *) PyObject_CallFunction( @@ -2304,15 +2300,12 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (CHECK_SEEKABLE(raw) == NULL) { + if (_PyIOBase_check_seekable(raw, Py_True) == NULL) return -1; - } - if (CHECK_READABLE(raw) == NULL) { + if (_PyIOBase_check_readable(raw, Py_True) == NULL) return -1; - } - if (CHECK_WRITABLE(raw) == NULL) { + if (_PyIOBase_check_writable(raw, Py_True) == NULL) return -1; - } Py_INCREF(raw); Py_XSETREF(self->raw, raw); diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index c9ff825338f3e7..d3d537f6a1a0ef 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -87,50 +87,6 @@ _io__IOBase_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_seekable_impl(self); } -PyDoc_STRVAR(_io__IOBase__checkSeekable__doc__, -"_checkSeekable($self, /, *args)\n" -"--\n" -"\n"); - -#define _IO__IOBASE__CHECKSEEKABLE_METHODDEF \ - {"_checkSeekable", _PyCFunction_CAST(_io__IOBase__checkSeekable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase__checkSeekable__doc__}, - -static PyObject * -_io__IOBase__checkSeekable_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); - -static PyObject * -_io__IOBase__checkSeekable(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) - #else - # define KWTUPLE NULL - #endif - - static const char * const _keywords[] = { NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "_checkSeekable", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; - - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { - goto exit; - } - __clinic_args = args[0]; - return_value = _io__IOBase__checkSeekable_impl(self, cls, __clinic_args); - -exit: - Py_XDECREF(__clinic_args); - return return_value; -} - PyDoc_STRVAR(_io__IOBase_readable__doc__, "readable($self, /)\n" "--\n" @@ -151,50 +107,6 @@ _io__IOBase_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_readable_impl(self); } -PyDoc_STRVAR(_io__IOBase__checkReadable__doc__, -"_checkReadable($self, /, *args)\n" -"--\n" -"\n"); - -#define _IO__IOBASE__CHECKREADABLE_METHODDEF \ - {"_checkReadable", _PyCFunction_CAST(_io__IOBase__checkReadable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase__checkReadable__doc__}, - -static PyObject * -_io__IOBase__checkReadable_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); - -static PyObject * -_io__IOBase__checkReadable(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) - #else - # define KWTUPLE NULL - #endif - - static const char * const _keywords[] = { NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "_checkReadable", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; - - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { - goto exit; - } - __clinic_args = args[0]; - return_value = _io__IOBase__checkReadable_impl(self, cls, __clinic_args); - -exit: - Py_XDECREF(__clinic_args); - return return_value; -} - PyDoc_STRVAR(_io__IOBase_writable__doc__, "writable($self, /)\n" "--\n" @@ -215,50 +127,6 @@ _io__IOBase_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_writable_impl(self); } -PyDoc_STRVAR(_io__IOBase__checkWritable__doc__, -"_checkWritable($self, /, *args)\n" -"--\n" -"\n"); - -#define _IO__IOBASE__CHECKWRITABLE_METHODDEF \ - {"_checkWritable", _PyCFunction_CAST(_io__IOBase__checkWritable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase__checkWritable__doc__}, - -static PyObject * -_io__IOBase__checkWritable_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); - -static PyObject * -_io__IOBase__checkWritable(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) - #else - # define KWTUPLE NULL - #endif - - static const char * const _keywords[] = { NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "_checkWritable", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; - - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { - goto exit; - } - __clinic_args = args[0]; - return_value = _io__IOBase__checkWritable_impl(self, cls, __clinic_args); - -exit: - Py_XDECREF(__clinic_args); - return return_value; -} - PyDoc_STRVAR(_io__IOBase_fileno__doc__, "fileno($self, /)\n" "--\n" @@ -452,4 +320,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=cc302d8dc238cf37 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=98f212f95ac26d74 input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index febe4c412d9c70..de79f6c5b545d6 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -376,26 +376,15 @@ _io__IOBase_seekable_impl(PyObject *self) Py_RETURN_FALSE; } -/*[clinic input] -_io._IOBase._checkSeekable - - cls: defining_class - / - *args: object - -[clinic start generated code]*/ - -static PyObject * -_io__IOBase__checkSeekable_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=f9449595c526a9ed input=6cf1584801d4b564]*/ +PyObject * +_PyIOBase_check_seekable(PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(seekable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = get_io_state_by_cls(cls); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); iobase_unsupported(state, "File or stream is not seekable."); return NULL; } @@ -420,26 +409,16 @@ _io__IOBase_readable_impl(PyObject *self) Py_RETURN_FALSE; } -/*[clinic input] -_io._IOBase._checkReadable - - cls: defining_class - / - *args: object - -[clinic start generated code]*/ - -static PyObject * -_io__IOBase__checkReadable_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=2eefd0c6015d18d3 input=cb9e598f66479243]*/ +/* May be called with any object */ +PyObject * +_PyIOBase_check_readable(PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(readable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = get_io_state_by_cls(cls); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); iobase_unsupported(state, "File or stream is not readable."); return NULL; } @@ -464,26 +443,16 @@ _io__IOBase_writable_impl(PyObject *self) Py_RETURN_FALSE; } -/*[clinic input] -_io._IOBase._checkWritable - - cls: defining_class - / - *args: object - -[clinic start generated code]*/ - -static PyObject * -_io__IOBase__checkWritable_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=db0ec8af34f05a01 input=a385662e0b185943]*/ +/* May be called with any object */ +PyObject * +_PyIOBase_check_writable(PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(writable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = get_io_state_by_cls(cls); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); iobase_unsupported(state, "File or stream is not writable."); return NULL; } @@ -843,9 +812,9 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_WRITABLE_METHODDEF {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, - _IO__IOBASE__CHECKSEEKABLE_METHODDEF - _IO__IOBASE__CHECKREADABLE_METHODDEF - _IO__IOBASE__CHECKWRITABLE_METHODDEF + {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS}, + {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS}, + {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS}, _IO__IOBASE_FILENO_METHODDEF _IO__IOBASE_ISATTY_METHODDEF From fe8c256260bd5828db0687b38807e778feb677cb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 23 Feb 2023 13:26:10 +0100 Subject: [PATCH 25/54] Pass state to _check* functions Also remove them as private methods on the private iobase type --- Lib/test/test_io.py | 7 +++++-- Modules/_io/_iomodule.h | 18 +++++++++--------- Modules/_io/bufferedio.c | 25 +++++++++++++------------ Modules/_io/iobase.c | 14 +++----------- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 9bcc92a40c61df..cc16804fe21829 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4242,6 +4242,7 @@ def test_warn_on_dealloc_fd(self): def test_pickling(self): # Pickling file objects is forbidden + msg = "cannot pickle" for kwargs in [ {"mode": "w"}, {"mode": "wb"}, @@ -4256,8 +4257,10 @@ def test_pickling(self): 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/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index e90bfd9e4d7ee1..bf34aa58c95bf7 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -26,15 +26,6 @@ extern PyType_Spec textiowrapper_spec; extern PyType_Spec winconsoleio_spec; #endif -/* These functions are used as METH_NOARGS methods, are normally called - * with args=NULL, and return a new reference. - * BUT when args=Py_True is passed, they return a borrowed reference. - */ -extern PyObject* _PyIOBase_check_readable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_writable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_seekable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); - /* Helper for finalization. This function will revive an object ready to be deallocated and try to close() it. It returns 0 if the object can be destroyed, or -1 if it @@ -185,6 +176,15 @@ find_io_state_by_def(PyTypeObject *type) return get_io_state(mod); } +/* These functions are used as METH_NOARGS methods, are normally called + * with args=NULL, and return a new reference. + * BUT when args=Py_True is passed, they return a borrowed reference. + */ +extern PyObject* _PyIOBase_check_readable(_PyIO_State *state, PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_writable(_PyIO_State *state, PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_seekable(_PyIO_State *state, PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); + #ifdef MS_WINDOWS extern char _PyIO_get_console_type(PyObject *); #endif diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 36babd3055100d..18a0854c96adab 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1229,7 +1229,8 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) CHECK_CLOSED(self, "seek of closed file") - if (_PyIOBase_check_seekable(self->raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_seekable(state, self->raw, Py_True) == NULL) return NULL; target = PyNumber_AsOff_t(targetobj, PyExc_ValueError); @@ -1428,7 +1429,8 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_readable(state, raw, Py_True) == NULL) return -1; Py_XSETREF(self->raw, Py_NewRef(raw)); @@ -1440,7 +1442,6 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, return -1; _bufferedreader_reset_buf(self); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = ( Py_IS_TYPE(self, state->PyBufferedReader_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type) @@ -1784,7 +1785,8 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_writable(state, raw, Py_True) == NULL) return -1; Py_INCREF(raw); @@ -1798,7 +1800,6 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = ( Py_IS_TYPE(self, state->PyBufferedWriter_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type) @@ -2103,12 +2104,12 @@ _io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, PyObject *writer, Py_ssize_t buffer_size) /*[clinic end generated code: output=327e73d1aee8f984 input=620d42d71f33a031]*/ { - if (_PyIOBase_check_readable(reader, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_readable(state, reader, Py_True) == NULL) return -1; - if (_PyIOBase_check_writable(writer, Py_True) == NULL) + if (_PyIOBase_check_writable(state, writer, Py_True) == NULL) return -1; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->reader = (buffered *) PyObject_CallFunction( (PyObject *)state->PyBufferedReader_Type, "On", reader, buffer_size); @@ -2300,11 +2301,12 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_seekable(raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_seekable(state, raw, Py_True) == NULL) return -1; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) + if (_PyIOBase_check_readable(state, raw, Py_True) == NULL) return -1; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) + if (_PyIOBase_check_writable(state, raw, Py_True) == NULL) return -1; Py_INCREF(raw); @@ -2319,7 +2321,6 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = (Py_IS_TYPE(self, state->PyBufferedRandom_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type)); diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index de79f6c5b545d6..4849b4e3d70340 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -377,14 +377,13 @@ _io__IOBase_seekable_impl(PyObject *self) } PyObject * -_PyIOBase_check_seekable(PyObject *self, PyObject *args) +_PyIOBase_check_seekable(_PyIO_State *state, PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(seekable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); iobase_unsupported(state, "File or stream is not seekable."); return NULL; } @@ -411,14 +410,13 @@ _io__IOBase_readable_impl(PyObject *self) /* May be called with any object */ PyObject * -_PyIOBase_check_readable(PyObject *self, PyObject *args) +_PyIOBase_check_readable(_PyIO_State *state, PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(readable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); iobase_unsupported(state, "File or stream is not readable."); return NULL; } @@ -445,14 +443,13 @@ _io__IOBase_writable_impl(PyObject *self) /* May be called with any object */ PyObject * -_PyIOBase_check_writable(PyObject *self, PyObject *args) +_PyIOBase_check_writable(_PyIO_State *state, PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(writable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); iobase_unsupported(state, "File or stream is not writable."); return NULL; } @@ -811,11 +808,6 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_READABLE_METHODDEF _IO__IOBASE_WRITABLE_METHODDEF - {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, - {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS}, - {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS}, - {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS}, - _IO__IOBASE_FILENO_METHODDEF _IO__IOBASE_ISATTY_METHODDEF From d0a0d542b8d76e08b177b68a031f7cd4f7673d63 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 23 Feb 2023 21:17:11 +0100 Subject: [PATCH 26/54] Windows fix (first of many) --- Modules/_io/winconsoleio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 4e4343a63480a8..a992a5effe3ef2 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -154,8 +154,6 @@ typedef struct { wchar_t wbuf; } winconsoleio; -PyTypeObject PyWindowsConsoleIO_Type; - int _PyWindowsConsoleIO_closed(PyObject *self) { @@ -265,7 +263,8 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, int fd_is_own = 0; HANDLE handle = NULL; - assert(PyObject_TypeCheck(self, (PyTypeObject *)&PyWindowsConsoleIO_Type)); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + assert(PyObject_TypeCheck(self, state->PyWindowsConsoleIO_Type)); if (self->fd >= 0) { if (self->closefd) { /* Have to close the existing file first. */ From 6a813b48c1f4a637c6f3f2dd5a4124549501a399 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:01:20 +0000 Subject: [PATCH 27/54] fix conflict --- Modules/_io/_iomodule.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 490e15c03b896d..219298387d186a 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -642,19 +642,10 @@ iomodule_exec(PyObject *m) { _PyIO_State *state = get_io_state(m); -<<<<<<< HEAD /* DEFAULT_BUFFER_SIZE */ if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) { return -1; } -======= - // PyRawIOBase_Type(PyIOBase_Type) subclasses - &_PyBytesIOBuffer_Type, -#ifdef HAVE_WINDOWS_CONSOLE_IO - &PyWindowsConsoleIO_Type, -#endif -}; ->>>>>>> 3d872a74c8c16d4a077c2223f678b1f8f7e0e988 /* UnsupportedOperation inherits from ValueError and OSError */ state->unsupported_operation = PyObject_CallFunction( From 0689f21608ce47d023bad0cd2b53c0998a7252e9 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:11:10 +0000 Subject: [PATCH 28/54] remove duplicate declarations --- Modules/_io/_iomodule.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 2fc2b66117291b..480913e4fd9d81 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -26,15 +26,6 @@ extern PyType_Spec textiowrapper_spec; extern PyType_Spec winconsoleio_spec; #endif /* HAVE_WINDOWS_CONSOLE_IO */ -/* These functions are used as METH_NOARGS methods, are normally called - * with args=NULL, and return a new reference. - * BUT when args=Py_True is passed, they return a borrowed reference. - */ -extern PyObject* _PyIOBase_check_readable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_writable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_seekable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); - /* Helper for finalization. This function will revive an object ready to be deallocated and try to close() it. It returns 0 if the object can be destroyed, or -1 if it From 5e19c48cb115f7d3a175a2df10df47fcffa44547 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:24:28 +0000 Subject: [PATCH 29/54] add missing methods --- Modules/_io/iobase.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 85409c93bfc055..41e9562767b2e9 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -204,6 +204,27 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +iobase_check_seekable(PyObject *self, PyObject *args) +{ + _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 = 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 = find_io_state_by_def(Py_TYPE(self)); + return _PyIOBase_check_writable(state, self, args); +} + /* 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. */ @@ -806,6 +827,11 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_READABLE_METHODDEF _IO__IOBASE_WRITABLE_METHODDEF + {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, + {"_checkSeekable", iobase_check_seekable, METH_NOARGS}, + {"_checkReadable", iobase_check_readable, METH_NOARGS}, + {"_checkWritable", iobase_check_writable, METH_NOARGS}, + _IO__IOBASE_FILENO_METHODDEF _IO__IOBASE_ISATTY_METHODDEF From 6099d5b9b8d2ccf0e9ddf7ffeeece69a79fbe036 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:48:31 +0000 Subject: [PATCH 30/54] fix pickling --- Modules/_io/iobase.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 41e9562767b2e9..aaf1f6f2dac635 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -225,6 +225,13 @@ iobase_check_writable(PyObject *self, PyObject *args) return _PyIOBase_check_writable(state, self, args); } +static PyObject * +iobase_reduce(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. */ @@ -842,6 +849,9 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_READLINES_METHODDEF _IO__IOBASE_WRITELINES_METHODDEF + {"__reduce__", iobase_reduce, METH_VARARGS}, + {"__reduce_ex__", iobase_reduce, METH_VARARGS}, + {NULL, NULL} }; From 18de9128d6d58636164b814ea1d1a1d8ec6db1a5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 14 Mar 2023 12:03:02 +0100 Subject: [PATCH 31/54] Add NEWS --- .../next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst 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 00000000000000..2232ea49382d13 --- /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 and Erlend E. Aasland. From c363eb80e97a45c443458365ba18fff31cacbb26 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 11:19:29 +0000 Subject: [PATCH 32/54] fix windows console check --- Modules/_io/_iomodule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 480913e4fd9d81..15bfaa3ca7eb7d 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -147,7 +147,7 @@ typedef struct { PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO PyTypeObject *PyWindowsConsoleIO_Type; #endif } _PyIO_State; From 73d581c4b6c5e53a5b9c0a8941051bfa6e879dc9 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 11:28:42 +0000 Subject: [PATCH 33/54] remove locale --- Modules/_io/_iomodule.c | 2 -- Modules/_io/_iomodule.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 219298387d186a..bae0dbe0fe8837 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -564,7 +564,6 @@ static int iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { _PyIO_State *state = get_io_state(mod); - Py_VISIT(state->locale_module); Py_VISIT(state->unsupported_operation); Py_VISIT(state->PyBufferedIOBase_Type); @@ -592,7 +591,6 @@ static int iomodule_clear(PyObject *mod) { _PyIO_State *state = get_io_state(mod); - Py_CLEAR(state->locale_module); Py_CLEAR(state->unsupported_operation); Py_CLEAR(state->PyBufferedIOBase_Type); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 15bfaa3ca7eb7d..cac7b2514c210c 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -128,8 +128,6 @@ extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err); extern PyModuleDef _PyIO_Module; typedef struct { - PyObject *locale_module; - PyObject *unsupported_operation; /* Types */ From eaf585e18d45c00df3c462c9017bc79f079a7402 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Wed, 15 Mar 2023 07:32:39 +0000 Subject: [PATCH 34/54] fix all windows checks --- Modules/_io/_iomodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index bae0dbe0fe8837..b10997a11f7282 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -580,7 +580,7 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->PyStringIO_Type); Py_VISIT(state->PyTextIOBase_Type); Py_VISIT(state->PyTextIOWrapper_Type); -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO Py_VISIT(state->PyWindowsConsoleIO_Type); #endif return 0; @@ -607,7 +607,7 @@ iomodule_clear(PyObject *mod) Py_CLEAR(state->PyStringIO_Type); Py_CLEAR(state->PyTextIOBase_Type); Py_CLEAR(state->PyTextIOWrapper_Type); -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO Py_CLEAR(state->PyWindowsConsoleIO_Type); #endif return 0; From 8d5b6a1a2aaf4a10f4505432177b0c4c9bb7d520 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 22 Mar 2023 13:01:55 +0100 Subject: [PATCH 35/54] Fix merge --- Python/pylifecycle.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7d98203a681f73..9cc5fa1b98931f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -695,11 +695,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; From e12eb85a1267c4b314ef5cded4497864ae0655e9 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 4 Apr 2023 16:16:31 +0530 Subject: [PATCH 36/54] use _PyType_GetModuleState --- Modules/_io/_iomodule.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index cac7b2514c210c..c78bb153968c4f 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -5,6 +5,7 @@ #include "exports.h" #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "structmember.h" /* Type specs */ @@ -161,7 +162,7 @@ get_io_state(PyObject *module) static inline _PyIO_State * get_io_state_by_cls(PyTypeObject *cls) { - void *state = PyType_GetModuleState(cls); + void *state = _PyType_GetModuleState(cls); assert(state != NULL); return (_PyIO_State *)state; } From 408c3b27ac315a95aaf417726dbbf03c991b471e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 18 Apr 2023 22:33:20 -0600 Subject: [PATCH 37/54] WIP --- Modules/_io/bufferedio.c | 27 +++++++++++++-------------- Modules/_io/bytesio.c | 10 +++++++++- Modules/_io/fileio.c | 2 +- Modules/_io/stringio.c | 11 +++++++---- Modules/_io/textio.c | 2 +- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index e935b73a42f301..2f658b9b5a26cd 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -368,6 +368,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) { @@ -379,7 +388,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; @@ -388,7 +396,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); } @@ -412,15 +420,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). */ @@ -2128,6 +2127,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; } @@ -2147,9 +2148,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); } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 6a7d9fad8a2a83..3fddfc2ed0bc9c 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1090,6 +1090,13 @@ bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view) b->exports--; } +static int +bytesiobuf_clear(bytesiobuf *self) +{ + Py_CLEAR(self->source); + return 0; +} + static int bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) { @@ -1104,7 +1111,7 @@ bytesiobuf_dealloc(bytesiobuf *self) PyTypeObject *tp = Py_TYPE(self); /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(self); - Py_CLEAR(self->source); + (void)bytesiobuf_clear(self); tp->tp_free(self); Py_DECREF(tp); } @@ -1112,6 +1119,7 @@ bytesiobuf_dealloc(bytesiobuf *self) static PyType_Slot bytesiobuf_slots[] = { {Py_tp_dealloc, bytesiobuf_dealloc}, {Py_tp_traverse, bytesiobuf_traverse}, + {Py_tp_clear, bytesiobuf_clear}, // Buffer protocol {Py_bf_getbuffer, bytesiobuf_getbuffer}, diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 44a04fa599af6b..1a286b29e526ff 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); } diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 1cd8e01b3ed466..c741f31cbdea98 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 303e86f832c9fb..a50f8f69bec348 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1403,7 +1403,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); } From 22b73a18d85b88aef0a987c1fe5ec39809ae9b46 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 28 Apr 2023 08:58:32 +0200 Subject: [PATCH 38/54] Visit and clear bytesio buf --- Modules/_io/bytesio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 3fddfc2ed0bc9c..80773058693259 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; } From 21470e61410afafe9aa03f1fc35839c6fb1c6fba Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 6 May 2023 21:55:45 +0200 Subject: [PATCH 39/54] Update NEWS --- .../next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 2232ea49382d13..4a73bbf32b370e 100644 --- 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 @@ -1,2 +1,2 @@ Isolate the :mod:`io` extension module by applying :pep:`687`. Patch by -Kumar Aditya and Erlend E. Aasland. +Kumar Aditya, Victor Stinner, and Erlend E. Aasland. From ce82d88c0152266d14f8ecf5dd6d8305cf969a56 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 6 May 2023 21:57:27 +0200 Subject: [PATCH 40/54] Minimise diff a little bit --- Modules/_io/_iomodule.c | 8 ++++---- Modules/_io/_iomodule.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ece26b113cf94d..cae599c79fc214 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -567,6 +567,8 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) _PyIO_State *state = get_io_state(mod); Py_VISIT(state->unsupported_operation); + Py_VISIT(state->PyIncrementalNewlineDecoder_Type); + Py_VISIT(state->PyRawIOBase_Type); Py_VISIT(state->PyBufferedIOBase_Type); Py_VISIT(state->PyBufferedRWPair_Type); Py_VISIT(state->PyBufferedRandom_Type); @@ -576,8 +578,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->PyBytesIO_Type); Py_VISIT(state->PyFileIO_Type); Py_VISIT(state->PyIOBase_Type); - Py_VISIT(state->PyIncrementalNewlineDecoder_Type); - Py_VISIT(state->PyRawIOBase_Type); Py_VISIT(state->PyStringIO_Type); Py_VISIT(state->PyTextIOBase_Type); Py_VISIT(state->PyTextIOWrapper_Type); @@ -594,6 +594,8 @@ iomodule_clear(PyObject *mod) _PyIO_State *state = get_io_state(mod); Py_CLEAR(state->unsupported_operation); + Py_CLEAR(state->PyIncrementalNewlineDecoder_Type); + Py_CLEAR(state->PyRawIOBase_Type); Py_CLEAR(state->PyBufferedIOBase_Type); Py_CLEAR(state->PyBufferedRWPair_Type); Py_CLEAR(state->PyBufferedRandom_Type); @@ -603,8 +605,6 @@ iomodule_clear(PyObject *mod) Py_CLEAR(state->PyBytesIO_Type); Py_CLEAR(state->PyFileIO_Type); Py_CLEAR(state->PyIOBase_Type); - Py_CLEAR(state->PyIncrementalNewlineDecoder_Type); - Py_CLEAR(state->PyRawIOBase_Type); Py_CLEAR(state->PyStringIO_Type); Py_CLEAR(state->PyTextIOBase_Type); Py_CLEAR(state->PyTextIOWrapper_Type); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index c78bb153968c4f..3cab2fee3903c1 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -132,6 +132,8 @@ typedef struct { PyObject *unsupported_operation; /* Types */ + PyTypeObject *PyIncrementalNewlineDecoder_Type; + PyTypeObject *PyRawIOBase_Type; PyTypeObject *PyBufferedIOBase_Type; PyTypeObject *PyBufferedRWPair_Type; PyTypeObject *PyBufferedRandom_Type; @@ -141,8 +143,6 @@ typedef struct { PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyIOBase_Type; - PyTypeObject *PyIncrementalNewlineDecoder_Type; - PyTypeObject *PyRawIOBase_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; From 3a9f5823dd1db02175d9b101a5527b05f9308ff2 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 6 May 2023 21:58:39 +0200 Subject: [PATCH 41/54] Add Py_mod_multiple_interpreters mod slot --- Modules/_io/_iomodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index cae599c79fc214..45f676eda79ce3 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -719,6 +719,7 @@ do { \ static struct PyModuleDef_Slot iomodule_slots[] = { {Py_mod_exec, iomodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; struct PyModuleDef _PyIO_Module = { .m_base = PyModuleDef_HEAD_INIT, From 13700b5903ae46dc37be2a56fa0a49d020cc05f8 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 6 May 2023 23:41:28 +0200 Subject: [PATCH 42/54] Fix pickling --- Modules/_io/_iomodule.h | 2 ++ Modules/_io/bufferedio.c | 8 ++++++++ Modules/_io/fileio.c | 2 ++ Modules/_io/iobase.c | 8 +++----- Modules/_io/textio.c | 3 +++ 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 3cab2fee3903c1..2ed4568b7733c3 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -184,6 +184,8 @@ extern PyObject* _PyIOBase_check_writable(_PyIO_State *state, PyObject *self, Py extern PyObject* _PyIOBase_check_seekable(_PyIO_State *state, PyObject *self, PyObject *args); extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); +extern PyObject *cannot_pickle(PyObject *self, PyObject *args); + #ifdef HAVE_WINDOWS_CONSOLE_IO extern char _PyIO_get_console_type(PyObject *); #endif diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 040f33828ccaec..d0a680a00718b6 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2390,6 +2390,9 @@ static PyMethodDef bufferedreader_methods[] = { {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, _IO__BUFFERED_TRUNCATE_METHODDEF {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + + {"__reduce__", cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", cannot_pickle, METH_VARARGS}, {NULL, NULL} }; @@ -2447,6 +2450,8 @@ static PyMethodDef bufferedwriter_methods[] = { _IO__BUFFERED_SEEK_METHODDEF {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + {"__reduce__", cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", cannot_pickle, METH_VARARGS}, {NULL, NULL} }; @@ -2562,6 +2567,9 @@ static PyMethodDef bufferedrandom_methods[] = { _IO__BUFFERED_PEEK_METHODDEF _IO_BUFFEREDWRITER_WRITE_METHODDEF {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + + {"__reduce__", cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", cannot_pickle, METH_VARARGS}, {NULL, NULL} }; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 8dd5e61b245028..45a99ca42f797a 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -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__", cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", cannot_pickle, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index aaf1f6f2dac635..3c24765d2f678f 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -225,8 +225,9 @@ iobase_check_writable(PyObject *self, PyObject *args) return _PyIOBase_check_writable(state, self, args); } -static PyObject * -iobase_reduce(PyObject *self, PyObject *args) { +PyObject * +cannot_pickle(PyObject *self, PyObject *args) +{ PyErr_Format(PyExc_TypeError, "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self))); return NULL; @@ -849,9 +850,6 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_READLINES_METHODDEF _IO__IOBASE_WRITELINES_METHODDEF - {"__reduce__", iobase_reduce, METH_VARARGS}, - {"__reduce_ex__", iobase_reduce, METH_VARARGS}, - {NULL, NULL} }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b772a511e9a83a..183e185166dbf2 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3216,6 +3216,9 @@ static PyMethodDef textiowrapper_methods[] = { _IO_TEXTIOWRAPPER_SEEK_METHODDEF _IO_TEXTIOWRAPPER_TELL_METHODDEF _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF + + {"__reduce__", cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", cannot_pickle, METH_VARARGS}, {NULL, NULL} }; From e8d0b57da8f9ae55bf0f14500c55e5c4cccc13a4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 6 May 2023 23:53:48 +0200 Subject: [PATCH 43/54] Make cannot-pickle function less smelly --- Modules/_io/_iomodule.h | 2 +- Modules/_io/bufferedio.c | 12 ++++++------ Modules/_io/fileio.c | 4 ++-- Modules/_io/iobase.c | 2 +- Modules/_io/textio.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 2ed4568b7733c3..fb2bb08871a5b9 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -184,7 +184,7 @@ extern PyObject* _PyIOBase_check_writable(_PyIO_State *state, PyObject *self, Py extern PyObject* _PyIOBase_check_seekable(_PyIO_State *state, PyObject *self, PyObject *args); extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); -extern PyObject *cannot_pickle(PyObject *self, PyObject *args); +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 d0a680a00718b6..041a30a8f3278c 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2391,8 +2391,8 @@ static PyMethodDef bufferedreader_methods[] = { _IO__BUFFERED_TRUNCATE_METHODDEF {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, - {"__reduce__", cannot_pickle, METH_VARARGS}, - {"__reduce_ex__", cannot_pickle, METH_VARARGS}, + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; @@ -2450,8 +2450,8 @@ static PyMethodDef bufferedwriter_methods[] = { _IO__BUFFERED_SEEK_METHODDEF {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, - {"__reduce__", cannot_pickle, METH_VARARGS}, - {"__reduce_ex__", cannot_pickle, METH_VARARGS}, + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; @@ -2568,8 +2568,8 @@ static PyMethodDef bufferedrandom_methods[] = { _IO_BUFFEREDWRITER_WRITE_METHODDEF {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, - {"__reduce__", cannot_pickle, METH_VARARGS}, - {"__reduce_ex__", cannot_pickle, METH_VARARGS}, + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 45a99ca42f797a..8fc2e3ae256788 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1166,8 +1166,8 @@ static PyMethodDef fileio_methods[] = { _IO_FILEIO_FILENO_METHODDEF _IO_FILEIO_ISATTY_METHODDEF {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, - {"__reduce__", cannot_pickle, METH_VARARGS}, - {"__reduce_ex__", cannot_pickle, METH_VARARGS}, + {"__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 3c24765d2f678f..c9bfaef2fa8083 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -226,7 +226,7 @@ iobase_check_writable(PyObject *self, PyObject *args) } PyObject * -cannot_pickle(PyObject *self, PyObject *args) +_PyIOBase_cannot_pickle(PyObject *self, PyObject *args) { PyErr_Format(PyExc_TypeError, "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self))); diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 183e185166dbf2..54863c87f8d0aa 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3217,8 +3217,8 @@ static PyMethodDef textiowrapper_methods[] = { _IO_TEXTIOWRAPPER_TELL_METHODDEF _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF - {"__reduce__", cannot_pickle, METH_VARARGS}, - {"__reduce_ex__", cannot_pickle, METH_VARARGS}, + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; From f1a5de0f63349133e7bfae6a71df41b23ef449dd Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 7 May 2023 12:25:00 +0200 Subject: [PATCH 44/54] Style nit --- Modules/_io/_iomodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 57ea0579f46436..945fdaf0c5eadc 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -724,7 +724,9 @@ static struct PyModuleDef_Slot iomodule_slots[] = { {Py_mod_exec, iomodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, -}; struct PyModuleDef _PyIO_Module = { +}; + +struct PyModuleDef _PyIO_Module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "io", .m_doc = module_doc, From 10788579438f9be610a7e103f0c268d556c4ca42 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 12:27:37 +0200 Subject: [PATCH 45/54] Reduce diff --- Modules/_io/_iomodule.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index a90105f441d832..1034ee8d90c918 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -676,11 +676,9 @@ do { \ } \ } while (0) - // Concrete classes + // Base classes ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); - - // Base classes ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL); // PyIOBase_Type subclasses From 3dad38886193b929d66ce4f7b083d5a97344431b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 12:29:43 +0200 Subject: [PATCH 46/54] Remove duplicate ADD_TYPE(PyBytesIOBuffer_Type...) --- Modules/_io/_iomodule.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1034ee8d90c918..9eec197474d047 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -702,8 +702,6 @@ do { \ // PyRawIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); - // XXX: should PyBytesIOBuffer_Type be subclass of PyRawIOBase_Type? - ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); #ifdef HAVE_WINDOWS_CONSOLE_IO ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, From 8df2633ae2566bfc84560cd2304ab3c50c0a6f5d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 13:04:15 +0200 Subject: [PATCH 47/54] Remove unneeded stylic change --- Modules/_io/_iomodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 01c6f85e97fbe4..235a39be0a7d86 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -640,9 +640,8 @@ iomodule_exec(PyObject *m) _PyIO_State *state = get_io_state(m); /* DEFAULT_BUFFER_SIZE */ - if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) { + if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) return -1; - } /* UnsupportedOperation inherits from ValueError and OSError */ state->unsupported_operation = PyObject_CallFunction( From 150587201d306c39eccdecbea5cb2074c24b7153 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 13:05:36 +0200 Subject: [PATCH 48/54] Reduce diff further --- Modules/_io/_iomodule.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 235a39be0a7d86..1d23445d6656e1 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -634,6 +634,18 @@ static PyMethodDef module_methods[] = { {NULL, NULL} }; +#define ADD_TYPE(module, type, spec, base) \ +do { \ + type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ + (PyObject *)base); \ + if (type == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(module, type) < 0) { \ + return -1; \ + } \ +} while (0) + static int iomodule_exec(PyObject *m) { @@ -661,18 +673,6 @@ iomodule_exec(PyObject *m) return -1; } -#define ADD_TYPE(module, type, spec, base) \ -do { \ - type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ - (PyObject *)base); \ - if (type == NULL) { \ - return -1; \ - } \ - if (PyModule_AddType(module, type) < 0) { \ - return -1; \ - } \ -} while (0) - // Base classes ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); From 6d55da9189cf27aa8e527428408740a81ccc75b6 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 12 May 2023 11:08:35 +0530 Subject: [PATCH 49/54] fixes by Victor --- Modules/_io/bufferedio.c | 1 - Modules/_io/textio.c | 1 - 2 files changed, 2 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 00698883c7697c..622088628a1d42 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2450,7 +2450,6 @@ static PyMethodDef bufferediobase_methods[] = { }; static PyType_Slot bufferediobase_slots[] = { - {Py_tp_dealloc, bufferediobase_dealloc}, {Py_tp_doc, (void *)bufferediobase_doc}, {Py_tp_methods, bufferediobase_methods}, {Py_tp_traverse, bufferediobase_traverse}, diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index ad8e7c74df3ca9..b6d1113f98f42e 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -196,7 +196,6 @@ static PyGetSetDef textiobase_getset[] = { }; static PyType_Slot textiobase_slots[] = { - {Py_tp_dealloc, textiobase_dealloc}, {Py_tp_doc, (void *)textiobase_doc}, {Py_tp_methods, textiobase_methods}, {Py_tp_getset, textiobase_getset}, From 80af518c8ccaa10b7abc39bdbe79664a75f7f788 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 12 May 2023 12:08:21 +0530 Subject: [PATCH 50/54] remove unused functions --- Modules/_io/bufferedio.c | 9 --------- Modules/_io/textio.c | 9 --------- 2 files changed, 18 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 622088628a1d42..471f849e1770f5 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2423,15 +2423,6 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, #include "clinic/bufferedio.c.h" #undef clinic_state -static void -bufferediobase_dealloc(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - tp->tp_free(self); - Py_DECREF(tp); -} - static int bufferediobase_traverse(PyObject *self, visitproc visit, void *arg) { diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b6d1113f98f42e..be0ba52c0b7308 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -171,15 +171,6 @@ textiobase_traverse(PyObject *self, visitproc visit, void *arg) return 0; } -static void -textiobase_dealloc(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - tp->tp_free((PyObject *)self); - Py_DECREF(tp); -} - static PyMethodDef textiobase_methods[] = { _IO__TEXTIOBASE_DETACH_METHODDEF _IO__TEXTIOBASE_READ_METHODDEF From 02dbef74471fa0767545df9277032e1eac833788 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 12 May 2023 12:14:39 +0530 Subject: [PATCH 51/54] use defining_class --- Modules/_io/bufferedio.c | 6 +++--- Modules/_io/iobase.c | 4 ++-- Modules/_io/textio.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 471f849e1770f5..d5cc047bd8d563 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -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 = find_io_state_by_def(Py_TYPE(self)); + _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 = find_io_state_by_def(Py_TYPE(self)); + _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 = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "write"); } diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 6ce34a1cbff857..0129ae5f62a7ef 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -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 = find_io_state_by_def(Py_TYPE(self)); + _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 = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "truncate"); } diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index be0ba52c0b7308..81dd3bed005a61 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 = find_io_state_by_def(Py_TYPE(self)); + _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 = find_io_state_by_def(Py_TYPE(self)); + _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 = find_io_state_by_def(Py_TYPE(self)); + _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 = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "write"); } From 8518ec5f5f673dce443dc7671e911640ab32034a Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 12 May 2023 12:17:00 +0530 Subject: [PATCH 52/54] remove rawiobase_dealloc --- Modules/_io/iobase.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 0129ae5f62a7ef..7a1f4643b72997 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -1034,15 +1034,6 @@ rawiobase_write(PyObject *self, PyObject *args) return NULL; } -static void -rawiobase_dealloc(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - tp->tp_free(self); - Py_DECREF(tp); -} - static int rawiobase_traverse(PyObject *self, visitproc visit, void *arg) { @@ -1059,7 +1050,6 @@ static PyMethodDef rawiobase_methods[] = { }; static PyType_Slot rawiobase_slots[] = { - {Py_tp_dealloc, rawiobase_dealloc}, {Py_tp_doc, (void *)rawiobase_doc}, {Py_tp_methods, rawiobase_methods}, {Py_tp_traverse, rawiobase_traverse}, From c5a430565ca7f88877fa36895129f95d4d0ec67d Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 12 May 2023 13:10:52 +0530 Subject: [PATCH 53/54] fix merge --- Modules/_io/_iomodule.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index a783a5bdb8a886..7b06c1bee5a832 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -577,7 +577,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { Py_VISIT(state->PyBytesIOBuffer_Type); Py_VISIT(state->PyBytesIO_Type); Py_VISIT(state->PyFileIO_Type); - Py_VISIT(state->PyIOBase_Type); Py_VISIT(state->PyStringIO_Type); Py_VISIT(state->PyTextIOBase_Type); Py_VISIT(state->PyTextIOWrapper_Type); @@ -604,7 +603,6 @@ iomodule_clear(PyObject *mod) { Py_CLEAR(state->PyBytesIOBuffer_Type); Py_CLEAR(state->PyBytesIO_Type); Py_CLEAR(state->PyFileIO_Type); - Py_CLEAR(state->PyIOBase_Type); Py_CLEAR(state->PyStringIO_Type); Py_CLEAR(state->PyTextIOBase_Type); Py_CLEAR(state->PyTextIOWrapper_Type); @@ -676,7 +674,6 @@ iomodule_exec(PyObject *m) } // 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); From ab1baf442949297b21a7d628bb214d0effdfd0b7 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 12 May 2023 13:17:06 +0530 Subject: [PATCH 54/54] fix merge --- Modules/_io/_iomodule.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index d1af6a5cdc131f..afd638a120ba08 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -158,7 +158,6 @@ struct _io_state { PyTypeObject *PyBytesIOBuffer_Type; PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; - PyTypeObject *PyIOBase_Type; PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type;