Lazarus

Programming => General => Topic started by: rwebb616 on April 19, 2021, 08:08:11 am

Title: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 08:08:11 am
I really hate inexplicable things... I have these two lines of code:

Code: Pascal  [Select][+][-]
  1.   setlabel('TitleLine1', 'Team ' + gameplay.starting.tostring, 80, 1);
  2.   setlabel('TitleLine2', 'Choose a Category:', 80, 2);


It goes through and executes the first line of code just fine... but then SIGSEGVs on the second one.  So I comment it out and further down in the block it makes several more calls to the setlabel function and all of those work just fine.  So I decide to move those two lines right below a block that creates and sets up a TPanel on my form - nothing special just sets a bunch of properties on it. 

Run the program - no crash.  I didn't change anything in the lines.. all I did was just simply move them below another piece of code and it works! 

Some people will be saying "Why are you writing on the forum then if your code is working?" ... as I said I hate inexplicable things!  How could I troubleshoot this? If it happens here it could happen elsewhere. 

Title: Re: Very Weird SIGSEGV
Post by: speter on April 19, 2021, 08:27:32 am
Without seeing more code, I don't think anyone can help you.
Is "setlabel()" a procedure you have written? Maybe it accesses a uninitialised variable/object.

Despite not being able to help much, I am definitely not suggesting that you shouldn't seek help when strange things happen. :)

cheers
S.
Title: Re: Very Weird SIGSEGV
Post by: dseligo on April 19, 2021, 08:36:40 am
Try to change it like this (if gameplay.starting is integer):

Code: Pascal  [Select][+][-]
  1.   setlabel('TitleLine1', 'Team ' + IntToStr(gameplay.starting), 80, 1);
  2.   setlabel('TitleLine2', 'Choose a Category:', 80, 2);

Maybe there is a bug in the helper.
Title: Re: Very Weird SIGSEGV
Post by: dbannon on April 19, 2021, 09:40:10 am
....
Run the program - no crash.  I didn't change anything in the lines.. all I did was just simply move them below another piece of code and it works! 

Some people will be saying "Why are you writing on the forum then if your code is working?" ... as I said I hate inexplicable things!  How could I troubleshoot this? If it happens here it could happen elsewhere.

rwebb, you are quite right to worry. It sounds to me like there is a memory problem somewhere, its possibly just chance where it pops up and tells the world. So, while you have hidden it for now, its still lurking in there, waiting for someone important to be watching ....

I would look for an uncreated object, an array you have not reserved enough space for and so on.  And try debugging, line by line through setlable() ....

Davo
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 03:27:43 pm
Without seeing more code, I don't think anyone can help you.
Is "setlabel()" a procedure you have written? Maybe it accesses a uninitialised variable/object.

Yes I knew when I posted it was a bit lacking in supplied information - just not sure the best way to post it considering this is a rather large project (to me anyways) - lots of things happening up to this point and I'm guessing any one of those things could be involved.  Since I am learning the language (and the windows aspects of the language - event driven code etc) I'm sure that it could be something that I forgot to "free" or maybe didn't create etc. 

The purpose of this particular function is to provision a TLabel and place it at a predetermined position on the screen.  The arguments are:


There is a labels object list that gets created at application startup and whenever a label is provisioned it's name is set according to the argument provided and then it is added to the objectlist.  Then when I try to "setlabel" and the name is the same as an existing one it will search for it in the objectlist and then return it if it exists or create a new one. 

So that is my first question - if a function returns an object as this does and I don't use the return value (don't do: var := setlabel()) is that a problem?  Setlabel is specific to this form and will place the label and "show" it

Quote
Despite not being able to help much, I am definitely not suggesting that you shouldn't seek help when strange things happen. :)
Yes, that is why I posted - thought it better to ask than leave it because I am sure I've not seen the last of it :)

Here is the code for the setlabel procedure:
Code: Pascal  [Select][+][-]
  1. Function TfGameboard.SetLabel(LabelName: String; Value: String;
  2.   FontSize: Integer; Location: Integer): TLabel;
  3. Var
  4.   index: Integer;
  5.   center: Integer;
  6.   labelcontrol: TLabel;
  7. Begin
  8.   center := self.Width Div 2;
  9.   labelcontrol := GetLabel(LabelName);
  10.   Result := labelcontrol;
  11.   With labelcontrol Do
  12.   Begin
  13.     Parent := self;
  14.     Caption := Value;
  15.     font.Size := FontSize;
  16.     Show;
  17.  
  18.     Case Location Of
  19.       1:
  20.       Begin         // Title line 1 location
  21.         Top := 80;
  22.         Left := center - Width Div 2;
  23.       End;
  24.       2:
  25.       Begin         // Title line 2 location
  26.         Top := 200;
  27.         Left := center - Width Div 2;
  28.       End;
  29.       3:
  30.       Begin         // Word location
  31.         Top := (self.Height Div 2) - Height Div 2;
  32.         Left := center - Width Div 2;
  33.       End;
  34.       4:
  35.       Begin         // Timer location
  36.         Top := (self.Height Div 2) - Height Div 2;
  37.         Left := center - Width Div 2;
  38.       End;
  39.       5:
  40.       Begin         // Word 1 Location
  41.         //Top := (self.height div 2) - height div 2;
  42.         top := 450;
  43.         Left := (center Div 2) - Width Div 2;
  44.       End;
  45.       6:
  46.       Begin         // Word 2 Location
  47.         //Top := (self.height div 2) - height div 2;
  48.         top := 450;
  49.         Left := center - Width Div 2;
  50.       End;
  51.       7:
  52.       Begin         // Word 3 Location
  53.         //Top := (self.height div 2) - height div 2;
  54.         top := 450;
  55.         Left := ((center Div 2) + center) - Width Div 2;
  56.       End;
  57.       8:
  58.       Begin         // Word 4 Location
  59.         //Top := (self.height div 2) - height div 2;
  60.         top := 650;
  61.         Left := (center Div 2) - Width Div 2;
  62.       End;
  63.       9:
  64.       Begin         // Word 5 Location
  65.         //Top := (self.height div 2) - height div 2;
  66.         top := 650;
  67.         Left := center - Width Div 2;
  68.       End;
  69.       10:
  70.       Begin         // Word 6 Location
  71.         //Top := (self.height div 2) - height div 2;
  72.         top := 650;
  73.         Left := ((center Div 2) + center) - Width Div 2;
  74.       End;
  75.       11:
  76.       Begin         // Word 7 Location
  77.         //Top := (self.height div 2) - height div 2;
  78.         top := 850;
  79.         Left := (center Div 2) - Width Div 2;
  80.       End;
  81.       12:
  82.       Begin         // Word 8 Location
  83.         //Top := (self.height div 2) - height div 2;
  84.         top := 850;
  85.         Left := center - Width Div 2;
  86.       End;
  87.       13:
  88.       Begin         // Word 9 Location
  89.         //Top := (self.height div 2) - height div 2;
  90.         top := 850;
  91.         Left := ((center Div 2) + center) - Width Div 2;
  92.       End;
  93.     End;
  94.   End;
  95. End;
  96.  

Also Pertinent is the GetLabel procedure:
Code: Pascal  [Select][+][-]
  1. function GetLabel(Name: String): TLabel;
  2. var
  3.   i,created:integer;
  4.   myLabel : TLabel;
  5. begin
  6.   Result := nil;
  7.   i:=0;
  8.   while i < labels.Count do begin
  9.     if (Tlabel(labels[i]).Name) = Name then begin
  10.       myLabel := Tlabel(labels[i]);
  11.       Result := myLabel;
  12.       exit;
  13.     end;
  14.     inc(i);
  15.   end;
  16.   // Existing label not found - create one and return the label
  17.   myLabel := TLabel.create(nil);
  18.   myLabel.Name:=Name;
  19.   myLabel.font.color := clWhite;
  20.   myLabel.font.name := 'Roboto Black';
  21.   created := labels.add(myLabel);
  22.   Result := TLabel(labels[created]);
  23. end;

I'm sure there are much better ways to do this but this is what I've come up with! :)
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 03:41:27 pm
Try to change it like this (if gameplay.starting is integer):

Code: Pascal  [Select][+][-]
  1.   setlabel('TitleLine1', 'Team ' + IntToStr(gameplay.starting), 80, 1);
  2.   setlabel('TitleLine2', 'Choose a Category:', 80, 2);

Maybe there is a bug in the helper.

Tried that just now and still get the error - it errors on the second line - the first one executes ok. 
I've also tried changing the name and the value of the second line and it makes no difference as long as it's in this spot in the code. 
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 03:46:40 pm

rwebb, you are quite right to worry. It sounds to me like there is a memory problem somewhere, its possibly just chance where it pops up and tells the world. So, while you have hidden it for now, its still lurking in there, waiting for someone important to be watching ....

I would look for an uncreated object, an array you have not reserved enough space for and so on.  And try debugging, line by line through setlable() ....

Problem is it won't even enter the procedure when I try to debug as soon as I hit F8 on the second line it gives me the error.

That is why I need help from all of you!  I need someone with more experience to help me learn how to debug this.  Maybe I'm foolish for attempting such a, well, "largish" project but at first glance when I started it seemed like a simple app to get my feet wet.  I'm finding it's much more involved than I first thought... although that is probably good - I like to be challenged and what better way to learn than to just jump in with both feet!

Rich
Title: Re: Very Weird SIGSEGV
Post by: howardpc on April 19, 2021, 03:53:33 pm
Obscure bugs are rarely found at third hand on the basis of code snippets posted on the forum.
Without sharing compilable sources I doubt that you'll get much more useful help.
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 04:11:10 pm
Also if it helps here is a little background on this project.  I'm recreating a game that was originally designed to run on a phone called "Heads Up" .. I'm changing it in that I'm making it to run on a large screen TV and modifying it to be a teams based game.  My plan is to use it for our church youth group as a game to play. 

It runs on the Windows platform due to it's use of the Windows API to embed the fonts and use them in memory.  I am trying to keep it all able to run with a single executable with no client libraries required.  Just drop the EXE on a Windows machine and run it and it has everything it needs to run.  The backgrounds I'm using are used in the project resources and loaded to change "boards" and I plan to embed the wave files that I'll need for sounds as well.

Right now I'm trying to just get the game working and figured I'd add sounds later.  I am using a gameloop that runs on a timer and I'm using logic state booleans to move the game through it's various stages. 

I know that I'm lacking a lot of Try / Except / Finally statements as I never really know quite the best way to use them. Always looking for improvement though and better ways to do stuff.

A very experienced programming friend of mine once told me... "If you want to make your program run better just delete some code" and it's funny because I'm finding out that is quite a true statement.  When I go back through a procedure that I've written I'm going "well, that complete block is unnecessary ... DELETE".  Seems like the first revision is always inefficient.
Rich
Title: Re: Very Weird SIGSEGV
Post by: Martin_fr on April 19, 2021, 04:11:37 pm
Problem is it won't even enter the procedure when I try to debug as soon as I hit F8 on the second line it gives me the error.

F7 is to enter.

F8 will step over, but not if something goes wrong inside. Though the debugger might stop, and show you where it went wrong. But not always.
To use the debugger, set debug type info to "dwarf with sets"

--
So use F7. Step in.
Before each step, have a close look at all the variables, parameters, locals... Maybe one of them is not what you expect.

Have you made sure the list, and all other objects involved are indeed created before the call? Yes I know, the firs call uses them too. But that does not mean anything. Could be luck.
If you deal with an uninitialized object, the code may crash, or may work. It may work once, but not twice....

Here is one thing to consider:
It is also possible that some code - even completely unrelated code - goes wrong, and due to uninitialized or range violation writes to memory it does not own. Then the error happens at some random place later. And moving code around may (or may not) hide the problem.

---
Have you set all the debug checks (range, object ...  checking)? -CRriot -gt  (also try -gtt or -gttt)
Turned optimization to zero -O-
Added Heaptrc -gh  (additionally search the forum for "keepreleased" option of Heaptrc)

If you are on Linux, instead of using Heaptrc, you can use valgrind.
Compile with -gv  and then start your app from console: valgrind --tool=memcheck yourapp
EDIT: posting overlapped / you are on Win



Title: Re: Very Weird SIGSEGV
Post by: ccrause on April 19, 2021, 04:28:25 pm
I was going to suggest proper debugging options, but Martin just beat me to it.  If you experience funny stepping during debugging, check that optimization is not set to higher than 1.

My guess is that something is messing up the stack. Are you perhaps manipulating strings or dynamic arrays in a "clever" way?
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 04:32:36 pm
Quote
F7 is to enter.

Well this helped a LOT... It seems I knew this but got so used to using F8 I didn't think of it.  Ok so now it's going into the GetLabel procedure and it goes through the while loop the first time for item 0 and then it chokes on item1.  I modified the loop as follows so I could see variable values because for some reason I can't get the value from labels.count but I can from a variable... same with Tlabel(labels).name:

Code: Pascal  [Select][+][-]
  1.   lcount := labels.Count;
  2.   while i < lcount do begin
  3.     lName := Tlabel(labels[i]).name;
  4.     if (Tlabel(labels[i]).Name) = Name then begin
  5.       myLabel := Tlabel(labels[i]);
  6.       Result := myLabel;
  7.       exit;
  8.     end;
  9.     inc(i);
  10.   end;

And when it hits LName where it is assigned the name of the TLabel it crashes.  So apparently I must not have set the name on one somewhere (not sure how given that the function does that) ... probably need to track all labels created start to this point and make sure they're being created properly now...

Quote
Have you set all the debug checks (range, object ...  checking)? -CRriot -gt  (also try -gtt or -gttt)
Turned optimization to zero -O-
Added Heaptrc -gh  (additionally search the forum for "keepreleased" option of Heaptrc)

No idea what all of those do - probably need to learn about that as well.  I'm not quite that advanced yet :)
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 04:34:40 pm
Are you perhaps manipulating strings or dynamic arrays in a "clever" way?

Not that I know of - at least not intentionally... I don't have any dynamic arrays at the moment .. I used to and then I moved to using a TFPObjectList instead. 
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 04:41:16 pm
Could it be this simple? 

Code: Pascal  [Select][+][-]
  1.  lcount := labels.Count;
  2.   while i < lcount do begin
  3.     lName := Tlabel(labels[i]).name;
  4.     if (Tlabel(labels[i]).Name) = Name then begin
  5.       myLabel := Tlabel(labels[i]);
  6.       Result := myLabel;
  7.       exit;
  8.     end;
  9.     inc(i);
  10.   end;                                      

labels.count is one based and the index for labels is zero based...

So shouldn't it be:
Code: Pascal  [Select][+][-]
  1. while i < lcount -1 do begin

This has bitten me before as well! :)

Rich
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 06:00:54 pm
Ok found the culprit.  Well it was a combination of things.  First was what I mentioned.. the zero based vs 1 based issue.  I also discovered that the while loop wasn't working as I expected it would so re-wrote it as a for loop:

Code: Pascal  [Select][+][-]
  1. for i:=0 to labels.count -1 do begin

Then I got another SIGSEGV but it got further.. tracked it down and realized that one of the labels in the labels object list was missing so I had obviously freed it at some point.  Tracked it down and sure enough I had freed one of the labels.  This was before I learned how the variables are pointers to the object in the list - I was thinking I was freeing the local object when I was actually freeing the one in the objectlist.  Commented that out and it was working again - no errors...

The primary help in this case was the suggestion of the F7 key which I knew about but had forgotten.  So THANK YOU for everyone who chimed in.  I'm sure I will eventually have more. 

Once I get this thing working maybe I'll post the code if people want to use it or do whatever with it.
Rich
Title: Re: Very Weird SIGSEGV
Post by: dseligo on April 19, 2021, 06:05:38 pm
Nice to hear you solved it.
Why do you have "Show;" in line 16 in function SetLabel?
Title: Re: Very Weird SIGSEGV
Post by: dseligo on April 19, 2021, 06:09:17 pm
So that is my first question - if a function returns an object as this does and I don't use the return value (don't do: var := setlabel()) is that a problem?  Setlabel is specific to this form and will place the label and "show" it

And I wanted to answer you to this one: if you don't need function result it's not a problem.
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 19, 2021, 06:09:34 pm
Why do you have "Show;" in line 16 in function SetLabel?

Ah.. very interesting you ask that question.  This was another brain buster for me for a while.  I couldn't figure out why my labels were not positioning correctly and after doing all the debugging I found out that until you actually "Show" a label the width value is apparently some default value I think of 65 .. I couldn't understand why all my labels were width 65 no matter what the caption was and so I tried showing one and checked it then the size was correct and everything centered as expected.  So if I show it first then position it, it happens so quickly that the user never sees it.

Rich
Title: Re: Very Weird SIGSEGV
Post by: speter on April 20, 2021, 02:15:41 am
Two things:
1) Regarding 'show', make sure you set your labels to .visible := true [I think] this could replace the 'show';
2) There was a comment earlier about debug settings:
[...] Have you set all the debug checks (range, object ...  checking)? -CRriot -gt  (also try -gtt or -gttt)
Turned optimization to zero -O-
Added Heaptrc -gh  (additionally search the forum for "keepreleased" option of Heaptrc)

I think you have these settings ON, but just in case: select Project > Project Options > Compiler Options > Debugging > Checks and Assertion. Set all the options (I/O, Range, Overflow, Stack, Verify methods calls & include assertion code). Also make sure "Generatie info for the debugger..." is ticked. Finally (in the bottom section) do a run with "Use Heaptrc..." ON.

cheers
S.
Title: Re: Very Weird SIGSEGV
Post by: egsuh on April 20, 2021, 04:25:03 am
I don't see any problem with while loop... probably other error may have influenced there. 
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 20, 2021, 04:29:00 am
I don't see any problem with while loop... probably other error may have influenced there.
I'm not sure but I think what was happening based on my line by line debug is that the while loop didn't run the code if the expression was true where the for loop ran regardless so for example if it ended up being:
Code: Pascal  [Select][+][-]
  1. for I:=0 to 0 do begin

based on count -1 being equal to zero then It would still run the code in the loop at least once. 

Rich
Title: Re: Very Weird SIGSEGV
Post by: Martin_fr on April 20, 2021, 04:57:18 am
I'm not sure but I think what was happening based on my line by line debug is that the while loop didn't run the code if the expression was true where the for loop ran regardless so for example if it ended up being:
Code: Pascal  [Select][+][-]
  1. for I:=0 to 0 do begin

based on count -1 being equal to zero then It would still run the code in the loop at least once. 

If "count - 1 = 0"  then "count = 1" therefore Item[0] does exist. So the loop can run once.

If "count = 0" then "count - 1 = -1"  and the loop would not run.


The only exception would be if count returned a "cardinal" because that can not go negative. But unless you have your own count function, that is not the case.
Title: Re: Very Weird SIGSEGV
Post by: egsuh on April 20, 2021, 05:40:24 am
This is not related with your problem, but for parsimony you can write followings:

   myLabel := TLabel.create(nil);
   myLabel.Name:=Name;
   myLabel.font.color := clWhite;
   myLabel.font.name := 'Roboto Black';
   created := labels.add(myLabel);
   Result := TLabel(labels[created]);

as:

   Result := TLabel.create(nil);
   labels.add(Result);
   Result.Name:=Name;
   Result.font.color := clWhite;
   Result.font.name := 'Roboto Black';
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 20, 2021, 07:33:52 am
I'm not sure but I think what was happening based on my line by line debug is that the while loop didn't run the code if the expression was true where the for loop ran regardless so for example if it ended up being:
Code: Pascal  [Select][+][-]
  1. for I:=0 to 0 do begin

based on count -1 being equal to zero then It would still run the code in the loop at least once. 

If "count - 1 = 0"  then "count = 1" therefore Item[0] does exist. So the loop can run once.

If "count = 0" then "count - 1 = -1"  and the loop would not run.


The only exception would be if count returned a "cardinal" because that can not go negative. But unless you have your own count function, that is not the case.

I believe it was the latter .. it was -1 but with the for loop even though it was -1 it still went through the loop at least once.  I'm still learning where each style of loop is best suited.  It seems experience is the best teacher :)

Rich
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on April 20, 2021, 07:36:50 am
This is not related with your problem, but for parsimony you can write followings:

   myLabel := TLabel.create(nil);
   myLabel.Name:=Name;
   myLabel.font.color := clWhite;
   myLabel.font.name := 'Roboto Black';
   created := labels.add(myLabel);
   Result := TLabel(labels[created]);

as:

   Result := TLabel.create(nil);
   labels.add(Result);
   Result.Name:=Name;
   Result.font.color := clWhite;
   Result.font.name := 'Roboto Black';


Ah yes, thank you for that.  I'm always looking for ways to make things read more simply. 
Title: Re: Very Weird SIGSEGV
Post by: egsuh on April 20, 2021, 08:21:30 am
Quote
with the for loop even though it was -1 it still went through the loop at least once.

No it doesn't, and it shouldn't.
Title: Re: Very Weird SIGSEGV
Post by: rwebb616 on May 03, 2021, 09:36:54 pm
Quote
No it doesn't, and it shouldn't.

Yes, I agree with this - in theory it should not and running a quick test app I find that it does not (as it shouldn't) but for some reason during my debugging the for loop was running when the while loop did not.  Perhaps it has to do with the point at which the counter gets increased.

Rich
TinyPortal © 2005-2018