@@ -126,6 +126,9 @@ static NPY_INLINE FILE *mpl_PyFile_Dup(PyObject *file, char *mode, mpl_off_t *or
126
126
*/
127
127
static NPY_INLINE int mpl_PyFile_DupClose (PyObject * file , FILE * handle , mpl_off_t orig_pos )
128
128
{
129
+ PyObject * exc_type = NULL , * exc_value = NULL , * exc_tb = NULL ;
130
+ PyErr_Fetch (& exc_type , & exc_value , & exc_tb );
131
+
129
132
int fd ;
130
133
PyObject * ret ;
131
134
mpl_off_t position ;
@@ -136,25 +139,33 @@ static NPY_INLINE int mpl_PyFile_DupClose(PyObject *file, FILE *handle, mpl_off_
136
139
fclose (handle );
137
140
138
141
/* 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. */
140
145
fd = PyObject_AsFileDescriptor (file );
141
146
if (fd == -1 ) {
142
- return -1 ;
147
+ goto fail ;
143
148
}
144
149
if (mpl_lseek (fd , orig_pos , SEEK_SET ) != -1 ) {
145
150
if (position == -1 ) {
146
151
PyErr_SetString (PyExc_IOError , "obtaining file position failed" );
147
- return -1 ;
152
+ goto fail ;
148
153
}
149
154
150
155
/* Seek Python-side handle to the FILE* handle position */
151
156
ret = PyObject_CallMethod (file , (char * )"seek" , (char * )(MPL_OFF_T_PYFMT "i" ), position , 0 );
152
157
if (ret == NULL ) {
153
- return -1 ;
158
+ goto fail ;
154
159
}
155
160
Py_DECREF (ret );
156
161
}
162
+ PyErr_Restore (exc_type , exc_value , exc_tb );
157
163
return 0 ;
164
+ fail :
165
+ Py_XDECREF (exc_type );
166
+ Py_XDECREF (exc_value );
167
+ Py_XDECREF (exc_tb );
168
+ return -1 ;
158
169
}
159
170
160
171
static NPY_INLINE int mpl_PyFile_Check (PyObject * file )
@@ -200,14 +211,23 @@ static NPY_INLINE PyObject *mpl_PyFile_OpenFile(PyObject *filename, const char *
200
211
201
212
static NPY_INLINE int mpl_PyFile_CloseFile (PyObject * file )
202
213
{
214
+ PyObject * type , * value , * tb ;
215
+ PyErr_Fetch (& type , & value , & tb );
216
+
203
217
PyObject * ret ;
204
218
205
219
ret = PyObject_CallMethod (file , (char * )"close" , NULL );
206
220
if (ret == NULL ) {
207
- return -1 ;
221
+ goto fail ;
208
222
}
209
223
Py_DECREF (ret );
224
+ PyErr_Restore (type , value , tb );
210
225
return 0 ;
226
+ fail :
227
+ Py_XDECREF (type );
228
+ Py_XDECREF (value );
229
+ Py_XDECREF (tb );
230
+ return -1 ;
211
231
}
212
232
213
233
#ifdef __cplusplus
0 commit comments