-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[Bug]: double free when FT2Font constructor is interrupted by KeyboardInterrupt #21364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I tried adding a print just before |
I now have another repro, which fails everytime: python -c 'from matplotlib.ft2font import FT2Font; from matplotlib.cbook import _get_data_path; [FT2Font(str(_get_data_path("fonts/ttf/DejaVuSans.ttf"))) for _ in range(10000)]' which gives
(The OSError is expected, it's just a simple way to trigger an exception in the FT2Font init.) I haven't fully figured out what was happening, but my guess is that when an exception occurs in the body of PyFT2Font_init, it exits with a not-fully-inited FT2Font, whose deallocation then tries to clear some fields not yet completely setup. |
For me, this nearly immediately does:
so I raised the file limit, hitting Ctrl-C does:
|
This might be dependent upon the C/C++ runtime implementation.
…On Mon, Oct 18, 2021 at 3:47 PM Elliott Sales de Andrade < ***@***.***> wrote:
For me, this nearly immediately does:
Exception ignored in: <matplotlib.ft2font.FT2Font object at 0x7f498ccdbb30>
Traceback (most recent call last):
File "<string>", line 1, in <listcomp>
OSError: [Errno 24] Too many open files: '/home/elliott/code/matplotlib/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'
Traceback (most recent call last):
File "<string>", line 1, in <module>
SystemError: PyEval_EvalFrameEx returned NULL without setting an error
so I raised the file limit, hitting Ctrl-C does:
^CException ignored in: <matplotlib.ft2font.FT2Font object at 0x7f6d87118f50>
Traceback (most recent call last):
File "<string>", line 1, in <listcomp>
KeyboardInterrupt
Traceback (most recent call last):
File "<string>", line 1, in <module>
SystemError: PyEval_EvalFrameEx returned NULL without setting an error
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#21364 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACHF6CBN232K3KNTLESDS3UHR2TNANCNFSM5GBKV3CA>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
The crash occurs in 3.8+, but not 3.7. |
This can be reproduced in valgrind:
The important part is the initial free in the second backtrace. We're in our wrapper deallocation function I'm not sure if that recursion is a bug in Python or not, but it's easy enough to work around on our side by disabling the callback on shutdown. |
Thanks for the investigation :-) Actually, I guess the fix may be rather to only catch exceptions occuring in close()? i.e. diff --git i/src/ft2font_wrapper.cpp w/src/ft2font_wrapper.cpp
index c0e2a20a1a..300b37ce64 100644
--- i/src/ft2font_wrapper.cpp
+++ w/src/ft2font_wrapper.cpp
@@ -297,6 +297,8 @@ exit:
static void close_file_callback(FT_Stream stream)
{
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
PyFT2Font *self = (PyFT2Font *)stream->descriptor.pointer;
PyObject *close_result = NULL;
if (!(close_result = PyObject_CallMethod(self->py_file, "c
A914
lose", ""))) {
@@ -308,6 +310,7 @@ exit:
if (PyErr_Occurred()) {
PyErr_WriteUnraisable((PyObject*)self);
}
+ PyErr_Restore(type, value, traceback);
}
static PyTypeObject PyFT2FontType; At least this fixes the issue for me. I guess this could still be a problem if close() throws an exception, but I'm not sure if that can happen at all (note that this would be the close() method of the file object returned by open(filename_passed_to_FT2Font), so it's a "standard" file-like, not a custom object (if we directly pass a file-like object to FT2Font, it doesn't get closed on destruction of the FT2Font as it is expected that the caller handles the file-like's lifetime). |
Well, |
Uh oh!
There was an error while loading. Please reload this page.
Bug summary
Ctrl-C'ing during construction of the font cache can occasionally result in a double-free error.
Code for reproduction
rm ~/.cache/matplotlib/fontlist*.json; \python -c 'import matplotlib.pyplot; print("done")' & sleep 2 && pkill -INT python
You may have to run this a couple of times and/or adjust the sleep time to see the problem.
Actual outcome
Expected outcome
Just the KeyboardInterrupt.
Operating system
arch linux and fedora (edited: confirmed on fedora as well)
Matplotlib Version
3.5.0.dev2291+gc8a902d3f2
Matplotlib Backend
mplcairo
Python version
3.9
Jupyter version
no
Other libraries
No response
Installation
No response
Conda channel
No response
The text was updated successfully, but these errors were encountered: