Lazarus

Free Pascal => General => Topic started by: TCH on July 30, 2018, 11:28:12 pm

Title: Same code works on x86, crashes on ARM
Post by: TCH on July 30, 2018, 11:28:12 pm
I have a small extension on TEdit, which works on x86, but on ARM a certain part crashes (namely line 65). Here is the code:
Code: Pascal  [Select][+][-]
  1. unit bitfield;
  2.  
  3. interface
  4.  
  5. uses Classes, Forms, StdCtrls, Controls;
  6.  
  7. type
  8.         TBitSent = procedure (Sender: TObject; bit: Boolean; pos: Integer) of object;
  9.  
  10.         TBitfield = class(TEdit)
  11.                 private
  12.                         FBitWidth: word;
  13.                         FBitSent: TBitSent;
  14.                         procedure SetBitWidth(w: Word);
  15.                         procedure KeyPress(Sender: TObject; var Key: Char);
  16.                         procedure SetBits(q: QWord);
  17.                         function GetBits: QWord;
  18.                 public
  19.                         var ID: QWord;
  20.                         property Bits: QWord read GetBits write SetBits;
  21.                         property BitWidth: Word read FBitWidth write SetBitWidth;
  22.                         property OnBitSent: TBitSent read FBitSent write FBitSent;
  23.                         constructor Create(TheOwner: TComponent);
  24.                         destructor Destroy;
  25.         end;
  26.  
  27. implementation
  28.  
  29. procedure TBitfield.SetBitWidth(w: Word);
  30. var
  31.         i: Integer;
  32.         add: String;
  33. begin
  34.         if (w > 64) then exit;
  35.         if (w < Self.FBitWidth) then
  36.         begin
  37.                 Self.Text := Copy(Self.Text, 1, w);
  38.         end
  39.         else
  40.         begin
  41.                 if (w > Self.FBitWidth) then
  42.                 begin
  43.                         add := '';
  44.                         for i := 1 to (w - Self.FBitWidth) do
  45.                         begin
  46.                                 add := add + '0';
  47.                         end;
  48.                         Self.Text := add + Self.Text;
  49.                 end;
  50.         end;
  51.         Self.FBitWidth := w;
  52. end;
  53.  
  54. procedure TBitfield.KeyPress(Sender: TObject; var Key: Char);
  55. var
  56.         pos, bp: Integer;
  57.         cp: TPoint;
  58. begin
  59.         pos := (Self.CaretPos.X + 1);
  60.         if (pos > Self.FBitWidth) then exit;
  61.         if ((Key = #48) or (Key = #49)) then
  62.         begin
  63.                 bp := Self.FBitWidth - pos;
  64.                 if (Self.FBitSent <> nil) then Self.FBitSent(Sender, Key <> #48, bp);
  65.                 Self.Text := Copy(Self.Text, 1, Self.CaretPos.X) + Key + Copy(Self.Text, pos + 1, bp); // this line crashes on ARM
  66.                 cp.X := pos - 1;
  67.                 cp.Y := 0;
  68.                 Self.CaretPos := cp;
  69.         end;
  70. end;
  71.  
  72. procedure TBitfield.SetBits(q: QWord);
  73. var
  74.         i: QWord;
  75.         s: String;
  76. begin
  77.         s := '';
  78.         i := QWord(1) shl (Self.FBitWidth - 1);
  79.         while (i > 0) do
  80.         begin
  81.                 s := s + chr(48 + integer((q and i) <> 0));
  82.                 i := i shr 1;
  83.         end;
  84.         Self.Text := s;
  85. end;
  86.  
  87. function TBitfield.GetBits: QWord;
  88. var i, j: Integer;
  89. begin
  90.         Result := 0;
  91.         i := Self.FBitWidth - 1;
  92.         for j := 1 to Self.FBitWidth do
  93.         begin
  94.                 Result := Result or (integer(Self.Text[j] <> #48) shl i);
  95.                 i := i shr 1;
  96.         end;
  97. end;
  98.  
  99. constructor TBitfield.Create(TheOwner: TComponent);
  100. begin
  101.         inherited Create(TheOwner);
  102.         Self.ReadOnly := True;
  103.         Self.OnKeyPress := TKeyPressEvent(@(Self.KeyPress));
  104.         Self.Text := '';
  105. end;
  106.  
  107. destructor TBitfield.Destroy;
  108. begin
  109.         inherited Destroy;
  110. end;
  111.  
  112. end.
  113.  
I've debugged it, it's not one of the Copy commands, if i put the result in a separate string, then it's works. It's the Self.Text := whatever; which crashes. But only in that function, all other assigns works. Is it because it's in a key press handling event? But the TEdit is read only, so no concurrent write would occur. And also, the corresponding line does not crashes on x86.

Any idea about this?

Also, does anybody know how can i replace a single character in a TEdit.Text? TEdit.Text[12] := 'a'; is not allowed...
Title: Re: Same code works on x86, crashes on ARM
Post by: howardpc on July 31, 2018, 12:22:25 am
Code: Pascal  [Select][+][-]
  1. var  s: TCaption;
  2. begin
  3.   ...
  4.   s := Edit1.Text;
  5.   s[12] := 'a';
  6.   Edit1.Text := s;
  7.   ...
  8. end;
Of course if Length(Edit1.Text) is  shorter than 12 this will give you problems...
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on July 31, 2018, 02:01:20 pm
What happens in the background if i do this? It will only reassign the pointer and then do the replace? Won't it copy the entire string two times?

Edit: I've checked the assembly and it does copy the entire string two times. The original just copied the two parts.

How can i obtain the real memory address of the text data of a TEdit?
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on July 31, 2018, 03:18:31 pm
What happens in the background if i do this?
Nothing. Your code is likely wrong as Howard pointed out.
Post a complete crashing example and I'll bet you it will be solved in seconds....
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on July 31, 2018, 06:53:36 pm
Howard gave a suggestion how to change one character, he did not pointed out about the code being wrong. If you mean the [12] offset, that was just an example, the crashing line is in the 65. line.

But here it is:
Code: Pascal  [Select][+][-]
  1. kecske := TBitfield.Create(Form1);
  2. kecske.Parent := TWinControl(Form1);
  3. kecske.BitWidth := 32;
And then if i press 1 or 0 in the box, then on x86, it works, on ARM it's chrashes.
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 02, 2018, 07:22:33 pm
It appears to me, you have lost the bet...
Title: Re: Same code works on x86, crashes on ARM
Post by: howardpc on August 02, 2018, 07:41:28 pm
I think Thaddy was asking you to post a complete compilable project (.lpi, .pas, .lpr, .lfm only).
It is usually impossible to properly debug a program only on the basis of a few code snippets taken from the presumed offending lines.
The location of a crash may not pinpoint the source of the bug(s), it may simply be the end of a longer trail.
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 06, 2018, 10:47:33 am
The complete project is a simple, freshly created Lazarus Application with everything default and with the unit in the starter post and the previous three lines in TForm.Create. Nothing else.
Title: Re: Same code works on x86, crashes on ARM
Post by: howardpc on August 06, 2018, 01:24:43 pm
Perhaps the implementation of TEdit on your ARM platform does not permit changes to TEdit.Text (via code) when ReadOnly is True? Easily tested by setting ReadOnly to False.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 06, 2018, 03:37:15 pm
Windows: just blocks input devices, including clipboard, but allows setting/changing content from code. (Windows quirk, bug)
Other widgetsets: read-only is read-only after initial content is set. Won't change anything not even from code.
For arm, claim the control, make it temporary read/write and set back to readonly when done.
Title: Re: Same code works on x86, crashes on ARM
Post by: Martin_fr on August 06, 2018, 03:39:27 pm
What options to compile to you use?

Have you tried to compile with -O-0 (no optimization), and all range and other checks enabled? -gh -Criot -gt

Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 06, 2018, 03:48:08 pm
What options to compile to you use?

Have you tried to compile with -O-0 (no optimization), and all range and other checks enabled? -gh -Criot -gt
That does not matter: a Windows control is read-only for input devices only. So it allows code to change it.
The other widget sets seem to be more strict: claim it, set to read write, change content and subsequently set to read-only again.

It is not related to optimization levels.
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 09, 2018, 07:05:34 pm
I tried to switch ReadOnly on and off, but did not helped.
However, it turned out, that it's does an access violation in cases, but i cannot figure it out. But it always does it on that line.

Here is the full source: http://oscomp.hu/depot/el_gpiot.zip

Currently there is a heatwave in Hungary and i'm suffering from thyroid issues, so i most probably did some lame error. I will appreciate if somebody pinpoints it...
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 09, 2018, 07:56:17 pm
line 161 you mean?
I suspect a rights issue. Try first to run the program as root. If that works we are close and I can write instructions to address the rights issue in a more reasonable fashion.
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 09, 2018, 08:05:04 pm
No, on line 64. in "bitfield.pas", it always crashes on that line:

Self.Text := Copy(Self.Text, 1, Self.CaretPos.X) + Key + Copy(Self.Text, pos + 1, bp);

I always use my machines as root.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 09, 2018, 08:16:12 pm
When I run the program compiled with FPC trunk and Lazarus trunk as sudo, at least my Raspberry Pi 3 shows up correct.
I made two small changes:
- I call Form1.BeginFormUpdate/Form1.EndFormUpdate in the init button to speed up painting.
- I changed the ridiculous try except to set the timer interval to
Code: Pascal  [Select][+][-]
  1.   i := strtointdef(Edit1.Text,10);
 

So the program works OK. See screenshot.
I saw more coding and layout issues, but those are for later. It works.
Can be that you need to upgrade to trunk versions.
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 09, 2018, 09:08:43 pm
No, you got it all wrong. As i told, the program crashes when you enter into the boxes and hit 1 or 0. Your changes are totally irrelevant to that. The program still crashes when editing the fields. And the problem is, that it works for the first N time, then suddenly it crashesh. If i change which TEdit i edit, then it crashes more easily.

Still, thanks for the strtointdef function, i wasn't aware of that function.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 09, 2018, 09:36:58 pm
As long as I run as sudo I can also repeatedly edit the edit boxes and it does not crash.(yet) but I use fpc3.1.1 + Lazarus 1.9.
What are you using? fpc version? Laz version?
I forgot that I also added cthreads, btw.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 10, 2018, 06:30:38 am
It still doesn't crash.... :D
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 10, 2018, 02:43:54 pm
I am running it as a root. FPC is 3.0.2 and Lazarus is 1.6.4.
It already had CThreads, as the relevant conditional macro has been commented out.

Please send me the binary you built and let me try it. If it does not crash, then the problem is inside the version of Lazarus/FPC i use. If it crash, then it's in my system.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 10, 2018, 03:33:22 pm
I am running it as a root. FPC is 3.0.2 and Lazarus is 1.6.4.
It already had CThreads, as the relevant conditional macro has been commented out.

Please send me the binary you built and let me try it. If it does not crash, then the problem is inside the version of Lazarus/FPC i use. If it crash, then it's in my system.
Ok. But you are using OLD versions and that's the cause!
I will put it on my website, too large to attach.

Link to binary is: http://thaddy.org/el_gpiot.zip compiled on RPi3 Rasbian-stretch. -O2 optimization.
It works. But note it is compiled with trunk. I suppose 3.0.4 and 1.8.4 will also do (but not old crap)
Title: Re: Same code works on x86, crashes on ARM
Post by: TCH on August 13, 2018, 01:36:50 pm
I have downloaded your binary and it crashes when i click on the Init button. It does not even get that far to show up the textfields...

Is there any repository for Debian armv7l with Lazarus 1.8 and FPC 3.0.4? Debian repo contains only old ones and Lazarus download page does not have any ARM download.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 13, 2018, 02:12:11 pm
Well. I thoroughly tested it and here it does not crash. It only crashes if you are not running as root or sudo. Maybe a dependency is missing on your computer? Or a raspi-config setting?
To obtain version 3.0.4 there are three options:
1. add stretch-backports to /etc/apt/sources.list. FPC 3.0.4 and Lazarus 1.8.4. are both in stretch-backports. You can subsequently install them with apt or apt-get
    You need to install with the -t option. See https://backports.debian.org/Instructions/
2. use fpcdeluxe
3. build from source. Here's how I do that.
step 0. sudo apt-get update && sudo apt-get dist-upgrade -y If you haven't done that for a long time.
step 1. check out the sources for fixes-3.0.4 or 3.1.1 trunk for fpc from svn
step 2. rename or copy the executable (not the symlink ) ppcarm to fpcstart and move it to your home directory.
           If /usr/local/bin/ppcarm is a symlink, the binary is here: /usr/local/lib/fpc/3.0.2/ppcarm or here /usr/lib/fpc/3.0.2/ppcarm
step 3. sudo apt-get remove fpc
step 4. change to the directory where you checked out the sources, probably /home/pi/fpc
step 5. sudo make clean all install  PP=/home/pi/fpcstart
step 6. sudo cp /usr/local/lib/fpc/3.0.4/ppcarm /usr/local/bin. use 3.1.1 instead of 3.0.4. if you use trunk.
step 7. type fpc -v in a terminal window. It should give you the new version.
step 8. sudo apt-get remove lazarus
step 9. check out the lazarus sources from git either 1.8.4 or trunk
step 10. goto the lazarus source directory
step 11. make clean all install
step 12. type ./startlazarus
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 13, 2018, 03:55:46 pm
@TCH
I reworked the code a bit and it seems a bit more stable (I could intermittently get an error, seldom, but still...After all...). I suspect that the runtime control creation had issues.
I will attach the code here later.
[edit]
Attached.
Title: Re: Same code works on x86, crashes on ARM
Post by: Thaddy on August 13, 2018, 09:54:17 pm
@TCH
Currently solving some issues regarding you not testing fpopen, fpclose, fpmmap and fpmunmap results.
I have introduced a EGpioException to handle those and made the procedures in el_gpiot into boolean functions.
Will attach code tomorrow. We're getting there. I also made everything range safe: it wasn't.
Title: Re: Same code works on x86, crashes on ARM
Post by: Jon on January 10, 2021, 08:10:08 pm
Sorry for reviving an old thread. Was el_gpiot ever updated? It compiles with trunk but GPIO's do not respond on my RPi3b.
TinyPortal © 2005-2018