@@ -667,7 +667,6 @@ struct textio
667667 PyObject_HEAD
668668 int ok ; /* initialized? */
669669 int detached ;
670- int flushing ; /* prevent reentrant detach during flush */
671670 Py_ssize_t chunk_size ;
672671 PyObject * buffer ;
673672 PyObject * encoding ;
@@ -726,16 +725,6 @@ struct textio
726725
727726#define textio_CAST (op ) ((textio *)(op))
728727
729- /* gh-143007 need to check for reentrant flush */
730- static inline int
731- _textiowrapper_flush (textio * self )
732- {
733- self -> flushing = 1 ;
734- int result = _PyFile_Flush ((PyObject * )self );
735- self -> flushing = 0 ;
736- return result ;
737- }
738-
739728static void
740729textiowrapper_set_decoded_chars (textio * self , PyObject * chars );
741730
@@ -905,6 +894,11 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info,
905894 PyObject * res ;
906895 int r ;
907896
897+ if (self -> detached > 0 ) {
898+ PyErr_SetString (PyExc_ValueError ,
899+ "underlying buffer has been detached" );
900+ return -1 ;
901+ }
908902 res = PyObject_CallMethodNoArgs (self -> buffer , & _Py_ID (readable ));
909903 if (res == NULL )
910904 return -1 ;
@@ -961,6 +955,11 @@ _textiowrapper_set_encoder(textio *self, PyObject *codec_info,
961955 PyObject * res ;
962956 int r ;
963957
958+ if (self -> detached > 0 ) {
959+ PyErr_SetString (PyExc_ValueError ,
960+ "underlying buffer has been detached" );
961+ return -1 ;
962+ }
964963 res = PyObject_CallMethodNoArgs (self -> buffer , & _Py_ID (writable ));
965964 if (res == NULL )
966965 return -1 ;
@@ -1007,6 +1006,11 @@ _textiowrapper_fix_encoder_state(textio *self)
10071006
10081007 self -> encoding_start_of_stream = 1 ;
10091008
1009+ if (self -> detached > 0 ) {
1010+ PyErr_SetString (PyExc_ValueError ,
1011+ "underlying buffer has been detached" );
1012+ return -1 ;
1013+ }
10101014 PyObject * cookieObj = PyObject_CallMethodNoArgs (
10111015 self -> buffer , & _Py_ID (tell ));
10121016 if (cookieObj == NULL ) {
@@ -1119,7 +1123,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
11191123
11201124 self -> ok = 0 ;
11211125 self -> detached = 0 ;
1122- self -> flushing = 0 ;
11231126
11241127 if (encoding == NULL ) {
11251128 PyInterpreterState * interp = _PyInterpreterState_GET ();
@@ -1434,7 +1437,7 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding,
14341437 return NULL ;
14351438 }
14361439
1437- if (_textiowrapper_flush ( self ) < 0 ) {
1440+ if (_PyFile_Flush (( PyObject * ) self ) < 0 ) {
14381441 return NULL ;
14391442 }
14401443 self -> b2cratio = 0 ;
@@ -1548,7 +1551,7 @@ _io_TextIOWrapper_closed_get_impl(textio *self);
15481551
15491552#define CHECK_ATTACHED (self ) \
15501553 CHECK_INITIALIZED(self); \
1551- if (self->detached) { \
1554+ if (self->detached > 0 ) { \
15521555 PyErr_SetString(PyExc_ValueError, \
15531556 "underlying buffer has been detached"); \
15541557 return NULL; \
@@ -1559,13 +1562,12 @@ _io_TextIOWrapper_closed_get_impl(textio *self);
15591562 PyErr_SetString(PyExc_ValueError, \
15601563 "I/O operation on uninitialized object"); \
15611564 return -1; \
1562- } else if (self->detached) { \
1565+ } else if (self->detached > 0 ) { \
15631566 PyErr_SetString(PyExc_ValueError, \
15641567 "underlying buffer has been detached"); \
15651568 return -1; \
15661569 }
15671570
1568-
15691571/*[clinic input]
15701572@critical_section
15711573_io.TextIOWrapper.detach
@@ -1577,12 +1579,18 @@ _io_TextIOWrapper_detach_impl(textio *self)
15771579{
15781580 PyObject * buffer ;
15791581 CHECK_ATTACHED (self );
1580- if (self -> flushing ) {
1582+ if (self -> detached < 0 ) {
15811583 PyErr_SetString (PyExc_RuntimeError ,
15821584 "reentrant call to detach() is not allowed" );
15831585 return NULL ;
15841586 }
1585- if (_textiowrapper_flush (self ) < 0 ) {
1587+ int entered = (self -> detached == 0 );
1588+ if (entered )
1589+ self -> detached = -1 ;
1590+ if (_PyFile_Flush ((PyObject * )self ) < 0 ) {
1591+ if (entered && self -> detached < 0 ) {
1592+ self -> detached = 0 ;
1593+ }
15861594 return NULL ;
15871595 }
15881596 buffer = self -> buffer ;
@@ -1653,11 +1661,15 @@ _textiowrapper_writeflush(textio *self)
16531661 Py_DECREF (pending );
16541662
16551663 PyObject * ret ;
1656- self -> flushing = 1 ;
1664+ CHECK_ATTACHED_INT (self );
1665+ int entered = (self -> detached == 0 );
1666+ if (entered )
1667+ self -> detached = -1 ;
16571668 do {
16581669 ret = PyObject_CallMethodOneArg (self -> buffer , & _Py_ID (write ), b );
16591670 } while (ret == NULL && _PyIO_trap_eintr ());
1660- self -> flushing = 0 ;
1671+ if (entered && self -> detached < 0 )
1672+ self -> detached = 0 ;
16611673 Py_DECREF (b );
16621674 // NOTE: We cleared buffer but we don't know how many bytes are actually written
16631675 // when an error occurred.
@@ -2602,7 +2614,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
26022614 goto fail ;
26032615 }
26042616
2605- if (_textiowrapper_flush ( self ) < 0 ) {
2617+ if (_PyFile_Flush (( PyObject * ) self ) < 0 ) {
26062618 goto fail ;
26072619 }
26082620
@@ -2649,7 +2661,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
26492661 goto fail ;
26502662 }
26512663
2652- if (_textiowrapper_flush ( self ) < 0 ) {
2664+ if (_PyFile_Flush (( PyObject * ) self ) < 0 ) {
26532665 goto fail ;
26542666 }
26552667
@@ -2776,7 +2788,7 @@ _io_TextIOWrapper_tell_impl(textio *self)
27762788
27772789 if (_textiowrapper_writeflush (self ) < 0 )
27782790 return NULL ;
2779- if (_textiowrapper_flush ( self ) < 0 ) {
2791+ if (_PyFile_Flush (( PyObject * ) self ) < 0 ) {
27802792 goto fail ;
27812793 }
27822794
@@ -2986,7 +2998,7 @@ _io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos)
29862998{
29872999 CHECK_ATTACHED (self )
29883000
2989- if (_textiowrapper_flush ( self ) < 0 ) {
3001+ if (_PyFile_Flush (( PyObject * ) self ) < 0 ) {
29903002 return NULL ;
29913003 }
29923004
@@ -3142,7 +3154,14 @@ _io_TextIOWrapper_flush_impl(textio *self)
31423154 self -> telling = self -> seekable ;
31433155 if (_textiowrapper_writeflush (self ) < 0 )
31443156 return NULL ;
3145- return PyObject_CallMethodNoArgs (self -> buffer , & _Py_ID (flush ));
3157+ int entered = (self -> detached == 0 );
3158+ if (entered ) {
3159+ self -> detached = -1 ;
3160+ }
3161+ PyObject * ret = PyObject_CallMethodNoArgs (self -> buffer , & _Py_ID (flush ));
3162+ if (entered && self -> detached < 0 )
3163+ self -> detached = 0 ;
3164+ return ret ;
31463165}
31473166
31483167/*[clinic input]
@@ -3169,7 +3188,7 @@ _io_TextIOWrapper_close_impl(textio *self)
31693188 if (r > 0 ) {
31703189 Py_RETURN_NONE ; /* stream already closed */
31713190 }
3172- if (self -> detached ) {
3191+ if (self -> detached > 0 ) {
31733192 Py_RETURN_NONE ; /* gh-142594 null pointer issue */
31743193 }
31753194 else {
@@ -3184,7 +3203,7 @@ _io_TextIOWrapper_close_impl(textio *self)
31843203 PyErr_Clear ();
31853204 }
31863205 }
3187- if (_textiowrapper_flush ( self ) < 0 ) {
3206+ if (_PyFile_Flush (( PyObject * ) self ) < 0 ) {
31883207 exc = PyErr_GetRaisedException ();
31893208 }
31903209
0 commit comments