Recent

Author Topic: [SOLVED] SIGSEGV on free pointer Tframe  (Read 2665 times)

superc

  • Full Member
  • ***
  • Posts: 241
[SOLVED] SIGSEGV on free pointer Tframe
« on: May 12, 2021, 10:09:26 am »
Hello,
I want to create dinamically tframe on  tpanel and free it for loading another; I use this code for create TFrame:

Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button1Click(Sender: TObject);
  2. var
  3.   hwnd: TFrame;
  4. begin
  5.   hwnd := CreateFrameAndHostPanel(pnlRight, pnlRight, pnlRight);
  6.   pntFrame := @hwnd;
  7.   ShowMessage(IntToStr(TFrameLEDMonitor(pntFrame^).getNumber));
  8.  
  9.   TFrameLEDMonitor(pntFrame^).Free;        
  10.  
  11. end;  
  12.  
  13. function TMonitorForm.CreateFrameAndHostPanel(_Owner: TComponent; _Parent: TWinControl; _Panel: TPanel): TFrame;
  14. begin
  15.   Result := FrameLcd.TFrameLCDMonitor.Create(Owner);
  16.   Try
  17.     Result.Parent := _Parent;
  18.   Except
  19.     FreeAndNil(Result);
  20.     raise;
  21.   End;
  22. end;  
  23.  
  24.  

In this code Free works well and free pointed frame, but if I move free line of code in another button like as:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button2Click(Sender: TObject);
  2. begin
  3.   TFrameLEDMonitor(pntFrame^).Free;
  4. end;      
  5.  

I get and SIGSEGV error and access violation; pntFrame is declared in public section and is typed as:

Code: Pascal  [Select][+][-]
  1. type
  2.   pointerTFrame = ^TFrame;                                      
  3.  

I don't understand why,

thanks in advance.
« Last Edit: May 14, 2021, 08:43:29 am by superc »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: SIGSEGV on free pointer Tframe
« Reply #1 on: May 12, 2021, 10:25:48 am »
You specified an owner when creating the frame. An owner (I assume the form) frees the owned class (the frame) on shutdown.

IIRC you can remove the owner registration using TComponent.RemoveComponent

superc

  • Full Member
  • ***
  • Posts: 241
Re: SIGSEGV on free pointer Tframe
« Reply #2 on: May 12, 2021, 10:29:07 am »
Excuse Marcov, I don't understand; i must remove owner as default passed with RemoveComponent?

Thanks
« Last Edit: May 12, 2021, 10:34:21 am by superc »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: SIGSEGV on free pointer Tframe
« Reply #3 on: May 12, 2021, 10:38:33 am »
Try declaring your public instance reference simply as
Code: Pascal  [Select][+][-]
  1. tempFrame: TFrameLEDMonitor;
and drop the local variable from your click event handler:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button1Click(Sender: TObject);begin
  2.   tempFrame := CreateFrameAndHostPanel(...);
  3.   ShowMessage(...);
  4.   tempFrame.Free;  tempFrame := Nil;
  5. end;
  6.  

superc

  • Full Member
  • ***
  • Posts: 241
Re: SIGSEGV on free pointer Tframe
« Reply #4 on: May 12, 2021, 11:04:52 am »
Try declaring your public instance reference simply as
Code: Pascal  [Select][+][-]
  1. tempFrame: TFrameLEDMonitor;
and drop the local variable from your click event handler:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button1Click(Sender: TObject);begin
  2.   tempFrame := CreateFrameAndHostPanel(...);
  3.   ShowMessage(...);
  4.   tempFrame.Free;  tempFrame := Nil;
  5. end;
  6.  

Works fine with
Code: Pascal  [Select][+][-]
  1.   public
  2.     { public declarations }
  3.     pntFrame: TFrame;      
  4.  

I've 5 Frame different, Thank you very much...






« Last Edit: May 12, 2021, 11:06:33 am by superc »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: SIGSEGV on free pointer Tframe
« Reply #5 on: May 12, 2021, 11:22:21 am »
First, you need to fully understand the concepts of owner and parent.

A component has an owner and parent property, both of which can be NIL (unassigned).

If you set the owner of component A to component B then B will free A when B shuts down. So owner is only about memory safety.

For the rest, that's where the parent comes in. Most importantly, the "parent" is generally how events flow and the order of form drawing. From parent to child, to the child's children etc.


Keeping this in mind, your CreateandFrameHostPanel is a bit weird, in 3 ways even:

Code: [Select]
function TMonitorForm.CreateFrameAndHostPanel(_Owner: TComponent; _Parent: TWinControl; _Panel: TPanel): TFrame;
begin
  Result := FrameLcd.TFrameLCDMonitor.Create(Owner);
  Try
    Result.Parent := _Parent;
  Except
    // owner.RemoveComponent(Result)
    FreeAndNil(Result);
    raise;
  End;
end;   

  • As said, on exception it is freed, but you also passed an owner. This will free the frame on exception, but leave a reference in the "owner"'s internal administration lingering. That's why removecompoent comes in, which I hopefully put in the right place
  • You pass "owner" to TFrameLCDMonitor.Create. This means you make the owner of the TMonitorForm also the owner of TFrameLCDMonitor. More logical would be to pass "Self" as owner, iow the Monintor form instance as owner
  • With "Parent" you make the same mistake. You pass the parent of the TMonitorForm instance, (TApplication?) which generally doesn't make sense. Self is more logical here too.

If you frame must be shown on top of some other component (e.g. a TPanel called "panel1") it is logical to make panel1 the owner and parent of the create form.

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: SIGSEGV on free pointer Tframe
« Reply #6 on: May 12, 2021, 04:55:53 pm »
while howardpc described a solution, I think there should be an explaination why the error occured in the first place.

First of all this has absolutely nothing to do with the owner, and a lack of RemoveComponent. Any component will call RemoveComponent on Free, so when handling components dynamically you don't need to care about the owner at all, it will be done all internally.

The problem is here:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button1Click(Sender: TObject);
  2. var
  3.   hwnd: TFrame;
  4. begin
  5.   hwnd := CreateFrameAndHostPanel(pnlRight, pnlRight, pnlRight);
  6.   pntFrame := @hwnd;
Here you assign a global variable the pointer of a local variable. As soon as this procedure finishes the local variable will go out of scope and any pointer to it, will be invalid, a so called dangling pointer.

When calling free from the other event handler:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button2Click(Sender: TObject);
  2. begin
  3.   TFrameLEDMonitor(pntFrame^).Free;
  4. end;
The previous event has already finished, meaning the pointer is dangling and when calling free, you dereference an invalid pointer. The segfault that occurs is because the memory referenced is invalid. In fact it is not because the pntFrame is dangling, your computer can not detect that, but a TFrame is also just a pointer and therefore the derefencing of Free causes the error because the invalid pointer points to something basically "random".

Long story short, never put pointer to local variables into global variables. Second, TFrame is already a pointer, all classes are hidden pointers in Pascal, so best is to skip the middle man and use TFrame directly instead of a pointer to TFrame

superc

  • Full Member
  • ***
  • Posts: 241
Re: SIGSEGV on free pointer Tframe
« Reply #7 on: May 14, 2021, 08:42:59 am »
while howardpc described a solution, I think there should be an explaination why the error occured in the first place.

First of all this has absolutely nothing to do with the owner, and a lack of RemoveComponent. Any component will call RemoveComponent on Free, so when handling components dynamically you don't need to care about the owner at all, it will be done all internally.

The problem is here:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button1Click(Sender: TObject);
  2. var
  3.   hwnd: TFrame;
  4. begin
  5.   hwnd := CreateFrameAndHostPanel(pnlRight, pnlRight, pnlRight);
  6.   pntFrame := @hwnd;
Here you assign a global variable the pointer of a local variable. As soon as this procedure finishes the local variable will go out of scope and any pointer to it, will be invalid, a so called dangling pointer.

When calling free from the other event handler:
Code: Pascal  [Select][+][-]
  1. procedure TMonitorForm.Button2Click(Sender: TObject);
  2. begin
  3.   TFrameLEDMonitor(pntFrame^).Free;
  4. end;
The previous event has already finished, meaning the pointer is dangling and when calling free, you dereference an invalid pointer. The segfault that occurs is because the memory referenced is invalid. In fact it is not because the pntFrame is dangling, your computer can not detect that, but a TFrame is also just a pointer and therefore the derefencing of Free causes the error because the invalid pointer points to something basically "random".

Long story short, never put pointer to local variables into global variables. Second, TFrame is already a pointer, all classes are hidden pointers in Pascal, so best is to skip the middle man and use TFrame directly instead of a pointer to TFrame

Now is all clear,
however Owner in this function I removed it from the code because it is useless,

thank you all.










 

TinyPortal © 2005-2018