Recent

Author Topic: Segfault at the very end of the program  (Read 30775 times)

balazsszekely

  • Guest
Re: Segfault at the very end of the program
« Reply #15 on: November 01, 2017, 10:41:05 am »
@TCH
It's very hard to give you an useful advice without actually seeing the code and without being able to debug it. However if you're sure that the exception occurs in those two lines and freeing objects is not an issue, just break the for loop when Application.Terminated is true:
Code: Pascal  [Select][+][-]
  1.   for i := 0 to tab_data[tabs.TabIndex].entrycount - 1 do
  2.   begin
  3.      if Application.Terminated then
  4.        Exit;
  5.        
  6.       infoimg[i].Picture.Clear;
  7.       infotx[i].Clear;
  8.       //...
  9.   end;
  10.  
  11.   for i := tab_data[tabs.TabIndex].scroll_pos to last_video do
  12.   begin
  13.      if Application.Terminated then
  14.        Exit;
  15.  
  16.       infotx[i].Top := ScrollBar1.Top + entry * space;
  17.       infoimg[i].Top := infotx[i].Top;
  18.       infoimg[i].Width := iw;
  19.       //...
  20.   end;
  21.  

Hope this helps...

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Segfault at the very end of the program
« Reply #16 on: November 01, 2017, 11:28:34 am »
@howardpc:
This is the creation's part:
Code: Pascal  [Select][+][-]
  1.      tabs := TButtonTabList.Create(Form1);
  2.      tabs.IgnoreTabTextChanges := true;
  3.      tabs.Left := 0;
  4.      tabs.Top := 24;
  5.      tabs.OnChange := @tabsChange;
  6.      tabs.OnCloseBtnClick := @tabsClose;
The rest would be too much to elaborate. I use it exactly like the normal TTabControl (actually i imitated it), but i needed a close button on all tabs. Here is the current beta of my program (not stripped, debug info is still inside), in which you can see what i would like to do with it: http://oscomp.hu/depot/ytfe.dbg

@GetMem:
Those functions don't run when the form is closed. Still i tried your idea, but no avail. I'm not sure that the exception occurs on those lines, but if i comment them out, then the program does not crash when exiting.

balazsszekely

  • Guest
Re: Segfault at the very end of the program
« Reply #17 on: November 01, 2017, 12:08:54 pm »
Quote
@TCH
Those functions don't run when the form is closed.
OK. Then my code is pretty much useless. I was under the impression those code segments are called on form close. I give up for now, since there is not enough information, unless you share more code of corse. If that's not an option then perhaps you should switch to another custom TAB component like:
1. ATTabs(http://wiki.freepascal.org/ATTabs)
2. TECTabCtrl from Eye-Candy Controls(http://wiki.freepascal.org/Eye-Candy_Controls)

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Segfault at the very end of the program
« Reply #18 on: November 01, 2017, 12:37:24 pm »
The rest would be too much to elaborate. I use it exactly like the normal TTabControl (actually i imitated it), but i needed a close button on all tabs. Here is the current beta of my program (not stripped, debug info is still inside), in which you can see what i would like to do with it: http://oscomp.hu/depot/ytfe.dbg

That "too much to elaborate" is the problem. I also tried your code and the instantiation example:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.tabsChange(Sender: TObject);
  2. begin
  3.  
  4. end;
  5.  
  6. procedure TForm1.tabsClose(Sender: TObject);
  7. begin
  8.  
  9. end;
  10.  
  11. procedure TForm1.FormCreate(Sender: TObject);
  12. begin
  13.   tabs := TButtonTabList.Create(Form1);
  14.   tabs.IgnoreTabTextChanges := true;
  15.   tabs.Left := 0;
  16.   tabs.Top := 24;
  17.   tabs.OnChange := @tabsChange;
  18.   tabs.OnCloseBtnClick := @tabsClose;
  19. end;

No problems there. But your component includes array definitions and like howardpc said, it doesn't construct or destroy. So it looks like you are left with unhandled object references when closing the program.

I suggest you narrow it down by creating a very simple program and build from there step by step to see when things start to go wrong.
keep it simple

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Segfault at the very end of the program
« Reply #19 on: November 01, 2017, 02:32:52 pm »
@GetMem:
Thanks for the suggestions, but it seems that these components require Lazarus 1.6 which means, i cannot use them on PPC OSX. Also, i would have to rewrite half of the program. As for the sources, i cannot really publish sources, because i would like to use the program for semi-commercial purposes when it's done.

@Munair:
It does not construct or destroy? It does create in the method of TButtonTabList.Synchronize;
As for destruction, on the previous page i was told to not destroy those components, for the form they're attached to will destroy them automatically.
What should i construct or destruct?

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Segfault at the very end of the program
« Reply #20 on: November 01, 2017, 03:39:04 pm »
If you create classes you should know about constructing and destructing of objects. It's what classes is all about.

As you do not provide the code I cannot tell you what to construct or destruct, so here is a very basic example:

Code: Pascal  [Select][+][-]
  1. type
  2.   TSomething = class
  3.   private
  4.     SomethingElse: TSomethingElse;
  5.   public
  6.     constructor Create;
  7.     destructor Destroy; override;
  8.   end;
  9.  
  10. constructor TSomething.Create;
  11. begin
  12.   inherited Create;
  13.   SomethingElse := TSomethingElse.Create;
  14. end;
  15.  
  16. destructor TSomething.Destroy;
  17. begin
  18.   SomethingElse.Free;
  19.   inherited Destroy;
  20. end;

Especially when creating object arrays you have to be careful as you may have to free objects by looping through all array elements.
keep it simple

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Segfault at the very end of the program
« Reply #21 on: November 01, 2017, 05:42:33 pm »
Huh? I'm confused... I've shared the unit's code (http://oscomp.hu/depot/buttontablist.pas) and also how i create it in the main code.
Code: Pascal  [Select][+][-]
  1.      tabs := TButtonTabList.Create(Form1);
  2.      tabs.IgnoreTabTextChanges := true;
  3.      tabs.Left := 0;
  4.      tabs.Top := 24;
  5.      tabs.OnChange := @tabsChange;
  6.      tabs.OnCloseBtnClick := @tabsClose;
What kind of construction or destruction is missing?

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Segfault at the very end of the program
« Reply #22 on: November 01, 2017, 11:11:24 pm »
Okay, now i think, it's something with the images. If i don't touch them, all is ok.
Code: Pascal  [Select][+][-]
  1. type TImageThread = class(TThread)
  2.         private
  3.         protected
  4.                 procedure Execute; override;
  5.                 procedure LoadAPicture;
  6.         public
  7.                 var TabIndex: integer;
  8.                 var NextTabIndex: integer;
  9.                 var CEI: integer;
  10.                 var Buffer: TMemoryStream;
  11.                 var ForceChange: boolean;
  12.                 var BlockChange: boolean;
  13.  
  14.                 constructor Create;
  15.                 destructor Destroy; override;
  16. end;
Code: Pascal  [Select][+][-]
  1. constructor TImageThread.Create;
  2. begin
  3.         inherited Create(True);
  4.         Self.Buffer := TMemoryStream.Create;
  5.         Self.TabIndex := -1;
  6.         Self.NextTabIndex := -1;
  7.         Self.ForceChange := False;
  8.         Self.BlockChange := False;
  9. end;
  10.  
  11. destructor TImageThread.Destroy;
  12. begin
  13.         Self.Buffer.Free;
  14.         inherited Destroy;
  15. end;
  16.  
  17. procedure TImageThread.LoadAPicture;
  18. begin
  19.      infoimg[Self.CEI].Picture.LoadFromStream(Self.Buffer);
  20. end;
  21.  
  22. procedure TImageThread.Execute;
  23. var
  24.    idx, cnt: Integer;
  25. begin
  26.      while (not Self.Terminated) do
  27.      begin
  28.           if ((Self.NextTabIndex <> Self.TabIndex) or (Self.ForceChange)) then
  29.           begin
  30.                Self.ForceChange := False;
  31.                Self.TabIndex := Self.NextTabIndex;
  32.                if (Self.BlockChange) then
  33.                begin
  34.                     Self.BlockChange := False;
  35.                     continue;
  36.                end;
  37.                if ((Self.TabIndex >= 0) and (Self.TabIndex < length(tab_data))) then
  38.                begin
  39.                    cnt := tab_data[TabIndex].entrycount - 1;
  40.                    for idx := 0 to cnt do
  41.                    begin
  42.                         if ((Self.NextTabIndex <> Self.TabIndex) or (Self.ForceChange) or (Self.Terminated)) then break;
  43.                         get_image_stream
  44.                         (
  45.                             tab_data[Self.TabIndex].entries[idx].code,
  46.                             tab_data[Self.TabIndex].entries[idx].img,
  47.                             Self.Buffer,
  48.                             tab_data[Self.TabIndex].entries[idx].force_reload
  49.                         );
  50.                         if ((Self.NextTabIndex <> Self.TabIndex) or (Self.ForceChange) or (Self.Terminated)) then break;
  51.                         tab_data[Self.TabIndex].entries[idx].force_reload := false;
  52.                         if (Self.Buffer.Size > 0) then
  53.                         begin
  54.                              Self.CEI := idx;
  55.                              Self.Buffer.Position := 0;
  56.                              Synchronize(@LoadAPicture);
  57.                         end;
  58.                    end;
  59.                end;
  60.           end;
  61.           sleep(50);
  62.      end;
  63. end;
If i comment out the line in LoadAPicture (or the call of that function), then all is ok. What can be the problem with this? Maybe the main thread and this thread tries to access the Image at the same time?
« Last Edit: November 01, 2017, 11:15:02 pm by TCH »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Segfault at the very end of the program
« Reply #23 on: November 01, 2017, 11:22:36 pm »
what are infoimg and tab_data? why there is no read/write protection on your data?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Segfault at the very end of the program
« Reply #24 on: November 01, 2017, 11:29:35 pm »
infoimg is an array of Images, attached to the main form. tab_data is an array of records which holds the tabs' data. Can i write protect an Image?

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Segfault at the very end of the program
« Reply #25 on: November 02, 2017, 12:33:15 am »
infoimg is an array of Images, attached to the main form. tab_data is an array of records which holds the tabs' data. Can i write protect an Image?
Image or imagelist? those are two different things. The common solution would be to create a TCriticalSection and make sure that you first aquire a lock from the critical section before accessing the data and most important make sure you release the lock afterwards even if there was an exception. As a rule of thumb it is unsafe to access lcl components from a thread simple don't do it.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Segfault at the very end of the program
« Reply #26 on: November 02, 2017, 07:28:17 am »
Code: Pascal  [Select][+][-]
  1. infoimg: Array[0..19] of TImage;
Last time i was told, that a thread can access the LCL elements via Synchronize. My program does that now. What do you suggest, how should i load the images from a separate thread?

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Segfault at the very end of the program
« Reply #27 on: November 02, 2017, 07:31:30 am »
As a rule of thumb it is unsafe to access lcl components from a thread simple don't do it.
That's not just Lazarus/FPC. It applies to most if not all programming languages. The ones I use(d) all gave the same advice.
keep it simple

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Segfault at the very end of the program
« Reply #28 on: November 02, 2017, 07:33:48 am »
Code: Pascal  [Select][+][-]
  1. infoimg: Array[0..19] of TImage;
Last time i was told, that a thread can access the LCL elements via Synchronize. My program does that now. What do you suggest, how should i load the images from a separate thread?
Threads are best used for calculation or other non-interface related tasks. Changing the interface from a thread is risky.
keep it simple

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Segfault at the very end of the program
« Reply #29 on: November 02, 2017, 01:36:45 pm »
Code: Pascal  [Select][+][-]
  1. infoimg: Array[0..19] of TImage;
Last time i was told, that a thread can access the LCL elements via Synchronize. My program does that now. What do you suggest, how should i load the images from a separate thread?
true synchronize executes the code in the context of the main application thread and that is safe.To load the images in a thread I usually create the timage control in the thread load the image and pass the image back to the main thread ready for use. The main thread will assign it to its place.

Do not reuse TImage from a thread you are setting your self for failure.

Edit : The above statement is a bit vague and I feel I have to elaborate a bit more.
It is ok to use a TImage control from a thread as long as you make sure that when used in the thread the main thread can not access it in any way. To use your example
If we assume that your code does not have any other reference for the TImage control in infoimg[Self.CEI] then the following is enough to make it  thread safe.
Code: Pascal  [Select][+][-]
  1. procedure TImageThread.LoadAPicture;
  2. var
  3.   vImage:TImage;
  4. begin
  5.   lock;
  6.   try
  7.     vImage.Picture.LoadFromStream(Self.Buffer);
  8.   finally
  9.     unlock;
  10.   end;
  11. end;
  12.  
that of course assumes that every time you want to access what is in infoimg[Self.CEI] you call lock. You can make things a bit less waiting by doing something along the lines of
Code: Pascal  [Select][+][-]
  1. procedure TImageThread.LoadAPicture;
  2. var
  3.   vImage:TImage;
  4. begin
  5.    lock;
  6.   vimage := infoimg[Self.CEI];
  7.   infoimg[Self.CEI] := nil;
  8.   unlock;
  9.   vImage.Picture.LoadFromStream(Self.Buffer);
  10.   lock;
  11.   infoimg[Self.CEI] := vImage;
  12.   unlock.
  13. end;
  14.  
In which case you allow your other code to check for nil before use and skip if its nil.

The moment you assign infoimg[Self.CEI] to a button or any other variable that might access it asynchrously with out calling your lock you cant trust that the data are properly protected from corruption and your only choice is something like.
Code: Pascal  [Select][+][-]
  1. procedure TImageThread.LoadAPicture;
  2. var
  3.   vImage:TImage;
  4. begin
  5.   vImage := TImage.Create(nil);//infoimg[Self.CEI];
  6.   vImage.Picture.LoadFromStream(Self.Buffer);
  7.   lock;
  8.   try
  9.     infoimg[Self.CEI].Free;
  10.     infoimg[Self.CEI] := vImage;
  11.   finally
  12.     unlock;
  13.   end;
  14. end;
  15.  

Oh if it is not apparent so far the lock protects  what happens in your array or cell (depends on how you have it set up) not what happens with the data of timage it self so even if you have call lock if the image is on a form or other control that paints it on the screen then you are not protected from corruption when calling loadfromstream from a thread.
« Last Edit: November 02, 2017, 03:03:43 pm by taazz »
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

 

TinyPortal © 2005-2018