Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit77bff5f

Browse files
committed
Don't abort on FT2Font weakref.
Currently, import weakref, matplotlib.ft2font weakref.ref(matplotlib.ft2font.FT2Font("/usr/share/fonts/TTF/DejaVuSans.ttf"))aborts Py3 with terminate called after throwing an instance of 'char const*' Fatal Python error: Abortedwhereas on Py2 a normal `TypeError: cannot create weak reference to'matplotlib.ft2font.FT2Font' object` is raised.This is because the following happens:- Py3 sets the TypeError for failure to create a weakref.- The FT2Font object gets GC'd as nothing is referring to it (yes, creating a weakref to a temporary is a bit silly).- The FT2Font destructor calls close_file_callback, which calls mpl_PyFile_DupClose, which calls PyObject_AsFileDescriptor... which, on Py3, calls the fileno() method on the file object.- PyObject_AsFileDescriptor fails because the originally set TypeError has not been cleared, so mpl_PyFile_DupClose likewise fails, causing close_file_callback to throw a C++ exception.Instead, carefully stash and restore the current exception state, bothin mpl_PyFile_DupClose, and likewise below, in mpl_PyFile_CloseFile (thelatter is needed because otherwise PyObject_CallMethod will clear theexception, cf comment in CPython's Objects/abstract.c: /* PyObject_Call() must not be called with an exception set, because it may clear it (directly or indirectly) and so the caller loses its exception */Note that if an exception *actually* gets raised by mpl_PyFile_DupCloseor mpl_PyFile_CloseFile, it will overwrite the TypeError. Strictlyspeaking, on Py3, it may be preferrable to chain the exceptions, butthis seems a bit overkill (mostly, I just want to avoid aborting thewhole Python process).
1 parentc0bceb1 commit77bff5f

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

‎src/file_compat.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ static NPY_INLINE FILE *mpl_PyFile_Dup(PyObject *file, char *mode, mpl_off_t *or
126126
*/
127127
staticNPY_INLINEintmpl_PyFile_DupClose(PyObject*file,FILE*handle,mpl_off_torig_pos)
128128
{
129+
PyObject*type=NULL,*value=NULL,*tb=NULL;
130+
PyErr_Fetch(&type,&value,&tb);
131+
129132
intfd;
130133
PyObject*ret;
131134
mpl_off_tposition;
@@ -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+
gotofail;
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+
gotofail;
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+
gotofail;
154159
}
155160
Py_DECREF(ret);
156161
}
162+
PyErr_Restore(type,value,tb);
157163
return0;
164+
fail:
165+
Py_XDECREF(type);
166+
Py_XDECREF(value);
167+
Py_XDECREF(tb);
168+
return-1;
158169
}
159170

160171
staticNPY_INLINEintmpl_PyFile_Check(PyObject*file)
@@ -200,14 +211,23 @@ static NPY_INLINE PyObject *mpl_PyFile_OpenFile(PyObject *filename, const char *
200211

201212
staticNPY_INLINEintmpl_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+
gotofail;
208222
}
209223
Py_DECREF(ret);
224+
PyErr_Restore(type,value,tb);
210225
return0;
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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp