GTK2: Recreating widget (i.e. while anchor docking) leeds to SIGSEGV in `function DeliverMouseUpMessage()`
- Lazarus/FPC Version: trunk
- Operating System: linux (Ubuntu 23.10, Debian 12)
- CPU / Bitness: 64
What happens
Problem is in function DeliverMouseUpMessage
, file lazarus/lcl/interfaces/gtk2/gtk2callback.inc:2271
.
I marked it with "!!!".
function DeliverMouseUpMessage(widget: PGtkWidget; event: pgdkEventButton;
AWinControl: TWinControl): boolean;
...
DeliverMessage(AWinControl, MessI);
// !!! at this point widget could be recreated, so local variable `Widget` can be illegal
if not AWinControl.HandleAllocated then
Result := True
else if MessI.Result <> 0 then
begin
// issue #19914
// !!! `AWinControl.Handle` is legal widget pointer
// !!! was: if GTK_IS_NOTEBOOK(Widget) then
if GTK_IS_NOTEBOOK({%H-}Pointer(AWinControl.Handle)) then
begin
if g_object_get_data({%H-}PGObject(AWinControl.Handle),'lclnotebookdragging') <> nil then
begin
g_object_steal_data({%H-}PGObject(AWinControl.Handle),'lclnotebookdragging');
exit;
end;
end;
// handled by the LCL
//DebugLn(['DeliverMouseUpMessage msg was handled by the LCL, Stopping signal ...']);
// !!! was: g_signal_stop_emission_by_name(PGTKObject(Widget), 'button-release-event');
Result := True;
end;
Steps to reproduce
- run
miniide1
- dock, for example, "FPDoc Editor" into "Messages"
- undock "Messages" out - all linux show errors in terminal output, like shown above
- repeat 2,3 several times - in Ubuntu 23.10 I got SIGSEGV
Patch
Also
I researched the same situations and found another possible bug, at line 2348:
function gtkMouseBtnRelease(widget: PGtkWidget; event : pgdkEventButton;
data: gPointer) : GBoolean; cdecl;
...
if DeliverMouseUpMessage(Widget, Event, TWinControl(Data)) then
begin
ReleaseMouseCapture;
if not DragManager.IsDragging then
Result := not CallBackDefaultReturn
else
begin
// workaround for gtk2 bug where "clicked" isn't triggered
// because of Result=TRUE and we started modal form from OnDropDown event.
// see issue http://bugs.freepascal.org/view.php?id=14318 for details.
if GTK_IS_BUTTON(Widget) then // !!!
begin
AForm := GetParentForm(TWinControl(Data));
if (AForm <> nil) and (fsModal in AForm.FormState) then
gtk_button_clicked(PGtkButton(Widget)); // !!!
end;
end;
end else
ReleaseMouseCapture;
if (csDesigning in TComponent(Data).ComponentState) then
begin
if (Event^.button = 3) then
begin
Result:=DeliverContextMenuMessage(widget,false); // !!!
end;
end;