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.
This commit is contained in:
Bad Sector 2023-10-19 20:38:09 +03:00
parent a37599119b
commit 6a5e16239a

View File

@ -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 }