TRadioGroup crashing after deleting a radiobutton from its Components list
- Lazarus/FPC Version:
- Operating System: Win 11
- CPU / Bitness: Intel, 64-bit
What happens
Usually radiobuttons are deleted from a RadioGroup by calling RadioGroup.Items.Delete(index)
. However, the group's radiobuttons are owned by the group, and thus a button can be deleted also by destroying it as Radiogroup.Components[index]
. When the user, afterwards, clicks on one of the items an access violation occurs.
Steps to reproduce
tradiogroup_deleteItem_crash.zip
Run attached the test project. It contains a radiogroup with three items. Delete the first item by clicking on the button which does this by calling RadioGroup.Components[0].Free
. Then click on one of the remaining buttons --> crash.
Analysis
Crashes after deleting sub-components usually are caused by a missing Notification
procedure, because this is the way the component to be deleted can tell other components that it is about to disappear. And in fact, this method is missing in TCustomRadioGroup
. The issue is that the internal FButtonList
is not notified that one of its elements will be destroyed.
Adding the following code to radiogroup.inc fixes the crash:
procedure TCustomRadioGroup.Notification(AComponent: TComponent; Operation: TOperation);
var
i: Integer;
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) then
for i := 0 to FButtonList.Count-1 do
if AComponent = TComponent(FButtonList[i]) then
begin
FButtonList.Delete(i);
Items.Delete(i);
exit;
end;
end;
I am not sure about Items.Delete(i)
, though. Without the Notification
method the destroyed item is not displayed any more, but the Items.Count
does not decrease (see the caption of the radiogroup in the test project which displays the ComponentCount
and Items.Count
values).
It is expected that the very similar TCheckgroup
should have the same issue. However, this is not true as you can see in the test project as well. Note however, that here again the Items.Count
does not change; but using the Notification
procedure proposed for TCustomRadioGroup
in TCustomCheckGroup
crashes here when Items.Delete(i)
is called.
So, something is missing in this solution...