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
Fix issue #2543 segfault in font dealloc after reinit #2548
Conversation
This should fix #2543 |
if (self->ttf_init_generation != current_ttf_generation) { | ||
// Since TTF_Font is a private structure | ||
// it's impossible to access face field in a common way. | ||
int** face_pp = font; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this is enough to stop the problem instead?
TTF_CloseFont(font);
font=NULL;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of tp_free further we are able not to aware about font. Therefore setting font to NULL is just redundant. Also font_dealloc is called only once after TTF_Quit to get a segfault inside a function TTF_CloseFont.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thanks for the explanation :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still not so clear about what
int **face_pp = font;
*face_pp = NULL;
does, exactly. Can you please explain this bit?
Anyways, I guess it is some weird hack, and I see it works because the tests pass :)
Thanks for looking into this @REW1L, sorry it's been dormant on our end for so long. Perhaps this should be turned into a more abstract "font object invalidation system," since something like this also segfaults: import pygame
import gc
pygame.font.init()
font = pygame.font.Font(None, 20)
pygame.font.quit()
pygame.font.init()
font.render("hello", True, "white")
print("rendered") # never happens, segfaults on the render But I still have some experimenting around this to do, I think. This is a weird situation / bug. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR looks good to me! Thanks for the PR 👍
Yeah since this fixes a segfault, it would be great to have this merged in ASAP, for v2.0.3
@REW1L there is a merge conflict that needs to be fixed before this being merged, if you want to fix it, you can go ahead! Or I can do it too if you'd like :)
I (hopefully) fixed the merge conflict. If it passes tests, we can merge it :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 🎉 Thanks
TTF_Quit frees all the resources allocated by freetype. However pointers to FT_Face from TTF_Font are not set to NULL after this. Therefore when font_dealloc tries to call TTF_CloseFont, FT_Done_Face is called on already freed object and segmentation fault appears.
It can be so when Font module quits and then GC is called. (test is provided)
Solution provided is a little hack for setting font->face to NULL. It will tell TTF_CloseFont that face has been already freed and all that's left is to free allocated SDL resources.
Also I had to introduce a field current_ttf_generation to the PyFontObject to understand if object passed to the font_dealloc function is being destructed after TTF_Quit.