You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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: Aborted
whereas 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, both
in mpl_PyFile_DupClose, and likewise below, in mpl_PyFile_CloseFile (the
latter is needed because otherwise PyObject_CallMethod will clear the
exception, 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_DupClose
or mpl_PyFile_CloseFile, it will overwrite the TypeError. Strictly
speaking, on Py3, it may be preferrable to chain the exceptions, but
this seems a bit overkill (mostly, I just want to avoid aborting the
whole Python process).
0 commit comments