@@ -68,11 +68,9 @@ PyDoc_STRVAR(iobase_doc,
6868 by whatever subclass. */
6969
7070_Py_IDENTIFIER (__IOBase_closed );
71- #define IS_CLOSED (self ) \
72- _PyObject_HasAttrId(self, &PyId___IOBase_closed)
73-
7471_Py_IDENTIFIER (read );
7572
73+
7674/* Internal methods */
7775static PyObject *
7876iobase_unsupported (const char * message )
@@ -131,6 +129,24 @@ iobase_truncate(PyObject *self, PyObject *args)
131129 return iobase_unsupported ("truncate" );
132130}
133131
132+ static int
133+ iobase_is_closed (PyObject * self )
134+ {
135+ PyObject * res ;
136+ /* This gets the derived attribute, which is *not* __IOBase_closed
137+ in most cases! */
138+ res = _PyObject_GetAttrId (self , & PyId___IOBase_closed );
139+ if (res == NULL ) {
140+ if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
141+ return -1 ;
142+ }
143+ PyErr_Clear ();
144+ return 0 ;
145+ }
146+ Py_DECREF (res );
147+ return 1 ;
148+ }
149+
134150/* Flush and close methods */
135151
136152/*[clinic input]
@@ -146,45 +162,60 @@ _io__IOBase_flush_impl(PyObject *self)
146162/*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/
147163{
148164 /* XXX Should this return the number of bytes written??? */
149- if (IS_CLOSED (self )) {
165+ int closed = iobase_is_closed (self );
166+
167+ if (!closed ) {
168+ Py_RETURN_NONE ;
169+ }
170+ if (closed > 0 ) {
150171 PyErr_SetString (PyExc_ValueError , "I/O operation on closed file." );
172+ }
173+ return NULL ;
174+ }
175+
176+ static PyObject *
177+ iobase_closed_get (PyObject * self , void * context )
178+ {
179+ int closed = iobase_is_closed (self );
180+ if (closed < 0 ) {
151181 return NULL ;
152182 }
153- Py_RETURN_NONE ;
183+ return PyBool_FromLong ( closed ) ;
154184}
155185
156186static int
157- iobase_closed (PyObject * self )
187+ iobase_check_closed (PyObject * self )
158188{
159189 PyObject * res ;
160190 int closed ;
161191 /* This gets the derived attribute, which is *not* __IOBase_closed
162192 in most cases! */
163- res = PyObject_GetAttr (self , _PyIO_str_closed );
164- if (res == NULL )
193+ res = _PyObject_GetAttrWithoutError (self , _PyIO_str_closed );
194+ if (res == NULL ) {
195+ if (PyErr_Occurred ()) {
196+ return -1 ;
197+ }
165198 return 0 ;
199+ }
166200 closed = PyObject_IsTrue (res );
167201 Py_DECREF (res );
168- return closed ;
169- }
170-
171- static PyObject *
172- iobase_closed_get (PyObject * self , void * context )
173- {
174- return PyBool_FromLong (IS_CLOSED (self ));
202+ if (closed <= 0 ) {
203+ return closed ;
204+ }
205+ PyErr_SetString (PyExc_ValueError , "I/O operation on closed file." );
206+ return -1 ;
175207}
176208
177209PyObject *
178210_PyIOBase_check_closed (PyObject * self , PyObject * args )
179211{
180- if (iobase_closed (self )) {
181- PyErr_SetString (PyExc_ValueError , "I/O operation on closed file." );
212+ if (iobase_check_closed (self )) {
182213 return NULL ;
183214 }
184- if (args == Py_True )
215+ if (args == Py_True ) {
185216 return Py_None ;
186- else
187- Py_RETURN_NONE ;
217+ }
218+ Py_RETURN_NONE ;
188219}
189220
190221/* XXX: IOBase thinks it has to maintain its own internal state in
@@ -204,9 +235,14 @@ _io__IOBase_close_impl(PyObject *self)
204235/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
205236{
206237 PyObject * res ;
238+ int closed = iobase_is_closed (self );
207239
208- if (IS_CLOSED (self ))
240+ if (closed < 0 ) {
241+ return NULL ;
242+ }
243+ if (closed ) {
209244 Py_RETURN_NONE ;
245+ }
210246
211247 res = PyObject_CallMethodObjArgs (self , _PyIO_str_flush , NULL );
212248
@@ -237,7 +273,7 @@ iobase_finalize(PyObject *self)
237273
238274 /* If `closed` doesn't exist or can't be evaluated as bool, then the
239275 object is probably in an unusable state, so ignore. */
240- res = PyObject_GetAttr (self , _PyIO_str_closed );
276+ res = _PyObject_GetAttrWithoutError (self , _PyIO_str_closed );
241277 if (res == NULL ) {
242278 PyErr_Clear ();
243279 closed = -1 ;
@@ -428,7 +464,7 @@ _PyIOBase_check_writable(PyObject *self, PyObject *args)
428464static PyObject *
429465iobase_enter (PyObject * self , PyObject * args )
430466{
431- if (_PyIOBase_check_closed (self , Py_True ) == NULL )
467+ if (iobase_check_closed (self ) )
432468 return NULL ;
433469
434470 Py_INCREF (self );
@@ -472,7 +508,7 @@ static PyObject *
472508_io__IOBase_isatty_impl (PyObject * self )
473509/*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/
474510{
475- if (_PyIOBase_check_closed (self , Py_True ) == NULL )
511+ if (iobase_check_closed (self ) )
476512 return NULL ;
477513 Py_RETURN_FALSE ;
478514}
@@ -499,24 +535,26 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
499535{
500536 /* For backwards compatibility, a (slowish) readline(). */
501537
502- int has_peek = 0 ;
503- PyObject * buffer , * result ;
538+ PyObject * peek , * buffer , * result ;
504539 Py_ssize_t old_size = -1 ;
505- _Py_IDENTIFIER (peek );
506540
507- if (_PyObject_HasAttrId (self , & PyId_peek ))
508- has_peek = 1 ;
541+ peek = _PyObject_GetAttrWithoutError (self , _PyIO_str_peek );
542+ if (peek == NULL && PyErr_Occurred ()) {
543+ return NULL ;
544+ }
509545
510546 buffer = PyByteArray_FromStringAndSize (NULL , 0 );
511- if (buffer == NULL )
547+ if (buffer == NULL ) {
548+ Py_XDECREF (peek );
512549 return NULL ;
550+ }
513551
514552 while (limit < 0 || PyByteArray_GET_SIZE (buffer ) < limit ) {
515553 Py_ssize_t nreadahead = 1 ;
516554 PyObject * b ;
517555
518- if (has_peek ) {
519- PyObject * readahead = _PyObject_CallMethodId ( self , & PyId_peek , "i" , 1 );
556+ if (peek != NULL ) {
557+ PyObject * readahead = PyObject_CallFunctionObjArgs ( peek , _PyLong_One , NULL );
520558 if (readahead == NULL ) {
521559 /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
522560 when EINTR occurs so we needn't do it ourselves. */
@@ -593,17 +631,19 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
593631
594632 result = PyBytes_FromStringAndSize (PyByteArray_AS_STRING (buffer ),
595633 PyByteArray_GET_SIZE (buffer ));
634+ Py_XDECREF (peek );
596635 Py_DECREF (buffer );
597636 return result ;
598637 fail :
638+ Py_XDECREF (peek );
599639 Py_DECREF (buffer );
600640 return NULL ;
601641}
602642
603643static PyObject *
604644iobase_iter (PyObject * self )
605645{
606- if (_PyIOBase_check_closed (self , Py_True ) == NULL )
646+ if (iobase_check_closed (self ) )
607647 return NULL ;
608648
609649 Py_INCREF (self );
@@ -716,7 +756,7 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines)
716756{
717757 PyObject * iter , * res ;
718758
719- if (_PyIOBase_check_closed (self , Py_True ) == NULL )
759+ if (iobase_check_closed (self ) )
720760 return NULL ;
721761
722762 iter = PyObject_GetIter (lines );
0 commit comments