@@ -126,6 +126,9 @@ static NPY_INLINE FILE *mpl_PyFile_Dup(PyObject *file, char *mode, mpl_off_t *or
126126 */
127127static NPY_INLINE int mpl_PyFile_DupClose (PyObject * file , FILE * handle , mpl_off_t orig_pos )
128128{
129+ PyObject * exc_type = NULL , * exc_value = NULL , * exc_tb = NULL ;
130+ PyErr_Fetch (& exc_type , & exc_value , & exc_tb );
131+
129132 int fd ;
130133 PyObject * ret ;
131134 mpl_off_t position ;
@@ -136,25 +139,33 @@ static NPY_INLINE int mpl_PyFile_DupClose(PyObject *file, FILE *handle, mpl_off_
136139 fclose (handle );
137140
138141 /* Restore original file handle position, in order to not confuse
139- Python-side data structures */
142+ Python-side data structures. Note that this would fail if an exception
143+ is currently set, which can happen as this function is called in cleanup
144+ code, so we need to carefully fetch and restore the exception state. */
140145 fd = PyObject_AsFileDescriptor (file );
141146 if (fd == -1 ) {
142- return -1 ;
147+ goto fail ;
143148 }
144149 if (mpl_lseek (fd , orig_pos , SEEK_SET ) != -1 ) {
145150 if (position == -1 ) {
146151 PyErr_SetString (PyExc_IOError , "obtaining file position failed" );
147- return -1 ;
152+ goto fail ;
148153 }
149154
150155 /* Seek Python-side handle to the FILE* handle position */
151156 ret = PyObject_CallMethod (file , (char * )"seek" , (char * )(MPL_OFF_T_PYFMT "i" ), position , 0 );
152157 if (ret == NULL ) {
153- return -1 ;
158+ goto fail ;
154159 }
155160 Py_DECREF (ret );
156161 }
162+ PyErr_Restore (exc_type , exc_value , exc_tb );
157163 return 0 ;
164+ fail :
165+ Py_XDECREF (exc_type );
166+ Py_XDECREF (exc_value );
167+ Py_XDECREF (exc_tb );
168+ return -1 ;
158169}
159170
160171static NPY_INLINE int mpl_PyFile_Check (PyObject * file )
@@ -200,14 +211,23 @@ static NPY_INLINE PyObject *mpl_PyFile_OpenFile(PyObject *filename, const char *
200211
201212static NPY_INLINE int mpl_PyFile_CloseFile (PyObject * file )
202213{
214+ PyObject * type , * value , * tb ;
215+ PyErr_Fetch (& type , & value , & tb );
216+
203217 PyObject * ret ;
204218
205219 ret = PyObject_CallMethod (file , (char * )"close" , NULL );
206220 if (ret == NULL ) {
207- return -1 ;
221+ goto fail ;
208222 }
209223 Py_DECREF (ret );
224+ PyErr_Restore (type , value , tb );
210225 return 0 ;
226+ fail :
227+ Py_XDECREF (type );
228+ Py_XDECREF (value );
229+ Py_XDECREF (tb );
230+ return -1 ;
211231}
212232
213233#ifdef __cplusplus
0 commit comments