From 6a5e16239a2ddd241af766b4a76217f22d7f5838 Mon Sep 17 00:00:00 2001 From: Bad Sector Date: Thu, 19 Oct 2023 20:38:09 +0300 Subject: [PATCH] LCL-GTK2: Fix double free in listview pixbuf due to wrong refcounting The 'pixbuf' field in GtkCellRendererPixbuf is supposed to be private to Gtk which handles refcounting itself, but LCL modifies it directly which can cause refcounting mismatches, especially during the destruction of a listview with icons (images are unref'd by both the listview destructor and gtk itself). Since it is exposed as a property it can be modified using the g_object_set_property and g_value_xxx APIs which handle any necessary refcounting, so this patch replaces the direct modification of the pixbuf field with these APIs. This fixes the crashes due to refcounting mismatch. --- lcl/interfaces/gtk2/gtk2wscustomlistview.inc | 33 ++++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/lcl/interfaces/gtk2/gtk2wscustomlistview.inc b/lcl/interfaces/gtk2/gtk2wscustomlistview.inc index 3680d9ddc0..2b0ff44f46 100644 --- a/lcl/interfaces/gtk2/gtk2wscustomlistview.inc +++ b/lcl/interfaces/gtk2/gtk2wscustomlistview.inc @@ -445,8 +445,12 @@ var ImageList: TCustomImageList; Bmp: TBitmap; pixbuf: PGdkPixbuf; + PixbufValue: TGValue; begin - PGtkCellRendererPixbuf(cell)^.pixbuf := nil; + PixbufValue:=Default(TGValue); + g_value_init(@PixbufValue, GDK_TYPE_PIXBUF); + g_object_set_property(G_OBJECT(cell), PChar('pixbuf'), @PixbufValue); + g_value_unset(@PixbufValue); Widgets := PTVWidgets(WidgetInfo^.UserData); gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]); @@ -488,15 +492,19 @@ begin pixbuf := nil; ImageList.GetBitmap(ImageIndex, Bmp); Gtk2_PixBufFromBitmap(Bmp,pixbuf); - PGtkCellRendererPixbuf(cell)^.pixbuf :=pixbuf; + g_value_init(@PixbufValue, GDK_TYPE_PIXBUF); + g_value_set_object(@PixbufValue, pixbuf); + g_object_set_property(G_OBJECT(cell), PChar('pixbuf'), @PixbufValue); + g_value_unset(@PixbufValue); finally Bmp.Free; end; end else - if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then - PGtkCellRendererPixbuf(cell)^.pixbuf := PGdkPixbuf(Images.Items[ImageIndex]) - else - PGtkCellRendererPixbuf(cell)^.pixbuf := nil; + g_value_init(@PixbufValue, GDK_TYPE_PIXBUF); + if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) and (Images.Items[ImageIndex] <> nil) then + g_value_set_object(@PixbufValue, PGdkPixbuf(Images.Items[ImageIndex])); + g_object_set_property(G_OBJECT(cell), PChar('pixbuf'), @PixbufValue); + g_value_unset(@PixbufValue); end; procedure Gtk2WSLV_ListViewGetPixbufDataFuncForIconView({%H-}cell_layout:PGtkCellLayout; @@ -507,8 +515,12 @@ var Widgets: PTVWidgets; ImageIndex: Integer; APath: PGtkTreePath; + PixbufValue: TGValue; begin - PGtkCellRendererPixbuf(cell)^.pixbuf := nil; + PixbufValue:=Default(TGValue); + g_value_init(@PixbufValue, GDK_TYPE_PIXBUF); + g_object_set_property(G_OBJECT(cell), 'pixbuf', @PixbufValue); + g_value_unset(@PixbufValue); Widgets := PTVWidgets(WidgetInfo^.UserData); gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]); @@ -529,10 +541,11 @@ begin ImageIndex := ListItem.ImageIndex; + g_value_init(@PixbufValue, GDK_TYPE_PIXBUF); if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then - PGtkCellRendererPixbuf(cell)^.pixbuf := PGdkPixbuf(Images.Items[ImageIndex]) - else - PGtkCellRendererPixbuf(cell)^.pixbuf := nil; + g_value_set_object(@PixbufValue, PGdkPixbuf(Images.Items[ImageIndex])); + g_object_set_property(G_OBJECT(cell), PChar('pixbuf'), @PixbufValue); + g_value_unset(@PixbufValue); end; { TGtk2WSCustomListView }