From 3105f5d7890269d3616b459699f37e8592ea956e Mon Sep 17 00:00:00 2001 From: Ivan Danilov Date: Sat, 3 Apr 2021 15:29:40 +0300 Subject: [PATCH 1/3] Fix segfault in font dealloc after reinit --- src_c/font.c | 13 +++++++++++-- src_c/include/pygame_font.h | 1 + test/font_test.py | 10 ++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src_c/font.c b/src_c/font.c index 3d62088e69..6dab220225 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -65,6 +65,7 @@ PyFont_New(TTF_Font *); #define PyFont_Check(x) ((x)->ob_type == &PyFont_Type) static int font_initialized = 0; +static uint current_ttf_generation = 0; static const char font_defaultname[] = "freesansbold.ttf"; static const char pkgdatamodule_name[] = "pygame.pkgdata"; static const char resourcefunc_name[] = "getResource"; @@ -188,6 +189,7 @@ font_autoquit(void) if (font_initialized) { font_initialized = 0; TTF_Quit(); + current_ttf_generation++; } } @@ -762,9 +764,15 @@ static void font_dealloc(PyFontObject *self) { TTF_Font *font = PyFont_AsFont(self); - - if (font && font_initialized) + if (font && font_initialized) { + 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; + *face_pp = NULL; + } TTF_CloseFont(font); + } if (self->weakreflist) PyObject_ClearWeakRefs((PyObject *)self); @@ -931,6 +939,7 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds) Py_XDECREF(oencoded); Py_DECREF(obj); self->font = font; + self->ttf_init_generation = current_ttf_generation; return 0; error: diff --git a/src_c/include/pygame_font.h b/src_c/include/pygame_font.h index 3fe4500a13..22db78774b 100644 --- a/src_c/include/pygame_font.h +++ b/src_c/include/pygame_font.h @@ -29,6 +29,7 @@ typedef struct { PyObject_HEAD TTF_Font* font; PyObject* weakreflist; + uint ttf_init_generation; } PyFontObject; #define PyFont_AsFont(x) (((PyFontObject*)x)->font) diff --git a/test/font_test.py b/test/font_test.py index 91d096a940..773a4d536e 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -206,6 +206,16 @@ def test_issue_font_alphablit(self): self.assertEqual(pre_blit_corner_pixel, post_blit_corner_pixel) + def test_segfault_after_reinit(self): + """ Reinitialization of font module should not cause + segmentation fault """ + import gc + font = pygame_font.Font(None, 20) + pygame_font.quit() + pygame_font.init() + del font + gc.collect() + def test_quit(self): pygame_font.quit() From ebaf47d699cd402e4d73129d542ef98a47dc3a2e Mon Sep 17 00:00:00 2001 From: Ivan Danilov Date: Sat, 3 Apr 2021 16:21:13 +0300 Subject: [PATCH 2/3] uint -> unsigned int --- src_c/font.c | 2 +- src_c/include/pygame_font.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src_c/font.c b/src_c/font.c index 6dab220225..c39ea9f7b9 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -65,7 +65,7 @@ PyFont_New(TTF_Font *); #define PyFont_Check(x) ((x)->ob_type == &PyFont_Type) static int font_initialized = 0; -static uint current_ttf_generation = 0; +static unsigned int current_ttf_generation = 0; static const char font_defaultname[] = "freesansbold.ttf"; static const char pkgdatamodule_name[] = "pygame.pkgdata"; static const char resourcefunc_name[] = "getResource"; diff --git a/src_c/include/pygame_font.h b/src_c/include/pygame_font.h index 22db78774b..00160c823d 100644 --- a/src_c/include/pygame_font.h +++ b/src_c/include/pygame_font.h @@ -29,7 +29,7 @@ typedef struct { PyObject_HEAD TTF_Font* font; PyObject* weakreflist; - uint ttf_init_generation; + unsigned int ttf_init_generation; } PyFontObject; #define PyFont_AsFont(x) (((PyFontObject*)x)->font) From 0888cb11ad8687e111c7eaee4ef19e0d93c07b98 Mon Sep 17 00:00:00 2001 From: Ivan Danilov Date: Sat, 3 Apr 2021 17:39:02 +0300 Subject: [PATCH 3/3] Ensure that font is NULL after freeing resources --- src_c/font.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src_c/font.c b/src_c/font.c index c39ea9f7b9..10af041615 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -772,6 +772,7 @@ font_dealloc(PyFontObject *self) *face_pp = NULL; } TTF_CloseFont(font); + self->font = NULL; } if (self->weakreflist)