Recent

Author Topic: Strange bugs with Advanced Records - SOLVED  (Read 3463 times)

ad1mt

  • Sr. Member
  • ****
  • Posts: 327
    • Mark Taylor's Home Page
Strange bugs with Advanced Records - SOLVED
« on: October 28, 2024, 08:15:52 pm »
EDIT: This problem has been solved... see my later post.
I'm getting strange bugs using advanced records with methods and a dynamic array inside.
In the following scenario...
Code: Pascal  [Select][+][-]
  1. type R=record {various bits'n'bobs} end;
  2. var u,v:R;
  3. procedure P(const p1:R; var p2:R); begin p2:=0 end;
  4. begin
  5. u:= 1;v:= u;
  6. P(v);
  7. // after the procedure call, the u variable also gets the value zero!
  8.  
...then after the procedure call, both the u & v variables get overwritten. This happens to the p1 and p2 parameters inside the procedure, and in u & v variables outside the procedure. And it happens, even though the u variable is passed to the procedure as a const parameter.
NB this problem is very intermittent; the above code is "example" code, and not guaranteed to run or produce the problem.
EDIT: I forgot to say that if the procedure is defined with an out parameter instead of a var parameter like this, then the problem disappears:
Code: Pascal  [Select][+][-]
  1. procedure P(const p1:R; out p2:R);
I have made some progress: it apears that when the assignment v:=u is done, the compiler sometimes copies a reference and not the record data. Then, when the v variable is accessed inside the procedure, it also overwrites the u variable.
I have worked around the problem, by creating a procedure that explicitly copies one record to another, e.g.
Code: Pascal  [Select][+][-]
  1. procedure copy_R(var P1,P2);begin P2.field:= P1.field; etc;end;
and use that instead of assignments like v:=u;
The problem is that I am creating a library, and if users of my library also hit the same problem, then they are going to get very strange bugs that will be impossible to fix.
I can't post my actual code because there is too much. I will have another attempt to try to produce some minimal code that shows the problem, and if successful I will post a follow-up.
I've been battling with this problem for many months now, and would welcome any suggestions. I have searched the internet but didn't get any good results. I am getting desperate.
Thanks.
« Last Edit: October 29, 2024, 09:34:40 am by ad1mt »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11941
  • FPC developer.
Re: Strange bugs with Advanced Records
« Reply #1 on: October 28, 2024, 08:23:13 pm »
If a problem is hard to reduce it might depend on somewhere else that is corrupting memory.

Anyway, reducing until reproduction is the only way.

Fibonacci

  • Hero Member
  • *****
  • Posts: 604
  • Internal Error Hunter
Re: Strange bugs with Advanced Records
« Reply #2 on: October 28, 2024, 08:24:13 pm »
constref

WooBean

  • Sr. Member
  • ****
  • Posts: 277
Re: Strange bugs with Advanced Records
« Reply #3 on: October 28, 2024, 08:34:14 pm »
Quote
I've been battling with this problem for many months now, and would welcome any suggestions.

Give us a chance to help you.  Do what Marcov asked.

My guess is that problem lies in {various bits'n'bobs} and
Code: Pascal  [Select][+][-]
  1.   u:= 1; // this is an opposite to what a record (advanced also) can accept.
  2.  

Platforms: Win7/64, Linux Mint Ulyssa/64

Bart

  • Hero Member
  • *****
  • Posts: 5467
    • Bart en Mariska's Webstek
Re: Strange bugs with Advanced Records
« Reply #4 on: October 28, 2024, 10:23:40 pm »
Pleas show some compileable code.

Bart

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1213
Re: Strange bugs with Advanced Records
« Reply #5 on: October 28, 2024, 11:25:55 pm »
I’m confused as well. How can you set a record to 1? Shouldn’t it be a field inside the record set to 1?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: Strange bugs with Advanced Records
« Reply #6 on: October 29, 2024, 12:23:00 am »
The real issue is that incomplete example of the Record definition leads everyone a stray.

Since "Advanced Records" was mentioned, I would venture to say that Operators for ":=" could be in use, this would allow to
assign a "0" to a record where the interaction is taking place within the OPERATOR := code body.

 Just my guess and I am sticking to it! :D

The only true wisdom is knowing you know nothing

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1213
Re: Strange bugs with Advanced Records
« Reply #7 on: October 29, 2024, 12:28:10 am »
Interesting how does that work?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: Strange bugs with Advanced Records
« Reply #8 on: October 29, 2024, 12:42:32 am »
Glad you ask!  :D
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeSwitch AdvancedRecords}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  10.  
  11. type
  12.  
  13.  { TMyRecord }
  14.  
  15.  TMyRecord = Record
  16.    P:Integer;
  17.    class operator := (ConstRef A:TmyRecord):integer;
  18.    Class operator := (B:Integer):TMyRecord;
  19.  end;
  20.  
  21.   { TForm1 }
  22.  
  23.   TForm1 = class(TForm)
  24.     Button1: TButton;
  25.     procedure Button1Click(Sender: TObject);
  26.   private
  27.  
  28.   public
  29.  
  30.   end;
  31.  
  32. var
  33.   Form1: TForm1;
  34.  
  35. implementation
  36.  
  37. {$R *.lfm}
  38.  
  39. { TMyRecord }
  40.  
  41. class operator TMyRecord.:=(ConstRef A: TmyRecord): integer;
  42. begin
  43.   Result := A.P;
  44. end;
  45.  
  46. class operator TMyRecord.:=(B: Integer): TMyRecord;
  47. begin
  48.   Result.P := B;
  49. end;
  50.  
  51. { TForm1 }
  52.  
  53. procedure TForm1.Button1Click(Sender: TObject);
  54. Var
  55.   M:TMyRecord;
  56.   I:integer;
  57. begin
  58.   M:= 1000;
  59.   I:= M;
  60.   Caption := I.ToString;
  61. end;
  62.  
  63. end.
  64.  
  65.  

Feast your eyes on that magic code! :-*
The only true wisdom is knowing you know nothing

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1213
Re: Strange bugs with Advanced Records
« Reply #9 on: October 29, 2024, 01:20:07 am »
Thanks for the code. Those overloaded operators are confusing  :D
I presume they are always like functions with a result?
I remember seeing something like this in c++ a long time ago. I guess it does make a good looking code using := .
« Last Edit: October 29, 2024, 01:30:20 am by Joanna from IRC »
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: Strange bugs with Advanced Records
« Reply #10 on: October 29, 2024, 01:30:13 am »
Quote
Why not use a property for setting values of record fields?

Well, that would make it more readable! what's the matter for you!  :)
The only true wisdom is knowing you know nothing

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1213
Re: Strange bugs with Advanced Records
« Reply #11 on: October 29, 2024, 01:32:53 am »
It just took me a moment to understand it. So it’s basically the same as doing record.field:= value. The only use case I can think of is if you want to set several fields to a given value.
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: Strange bugs with Advanced Records
« Reply #12 on: October 29, 2024, 02:10:48 am »
My last cryptic code pieace!  :D

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeSwitch AdvancedRecords}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  10.  
  11. type
  12.  
  13.  { TMyRecord }
  14.  
  15.  TMyRecord = Record
  16.    P:Integer;
  17.    X,Y:integer;
  18.    Function fGEtSetXY(inX,InY:Integer):TMyRecord;
  19.    class operator := (ConstRef A:TmyRecord):integer;
  20.    Class operator := (B:Integer):TMyRecord;
  21.    Property XY[iX,iY:Integer]:TMyRecord Read FGetSetXY; default;
  22.  end;
  23.  
  24.   { TForm1 }
  25.  
  26.   TForm1 = class(TForm)
  27.     Button1: TButton;
  28.     procedure Button1Click(Sender: TObject);
  29.   private
  30.  
  31.   public
  32.  
  33.   end;
  34.  
  35. var
  36.   Form1: TForm1;
  37.  
  38. implementation
  39.  
  40. {$R *.lfm}
  41.  
  42. { TMyRecord }
  43.  
  44. function TMyRecord.fGEtSetXY(inX, InY: Integer): TMyRecord;
  45. begin
  46.  X := inX;Y:=inY;
  47. Result := Self;
  48. end;
  49.  
  50. class operator TMyRecord.:=(ConstRef A: TmyRecord): integer;
  51. begin
  52.   Result := A.P;
  53. end;
  54.  
  55. class operator TMyRecord.:=(B: Integer): TMyRecord;
  56. begin
  57.   Result.P := B;
  58. end;
  59.  
  60. { TForm1 }
  61.  
  62. procedure TForm1.Button1Click(Sender: TObject);
  63. Var
  64.   M:TMyRecord;
  65.   I:integer;
  66. begin
  67.   M[100,200]; //Set the record's X,Y as a default;
  68.   M:= 1000;   //Set P variable;
  69.   I:= M;      // Assign I from M.P
  70.   Caption := I.ToString+':'+M.X.Tostring+','+M.Y.Tostring;
  71. end;
  72.  
  73. end.
  74.  
  75.  

That Default X,Y setting parameter should really spin your head around!

 :o
The only true wisdom is knowing you know nothing

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1213
Re: Strange bugs with Advanced Records
« Reply #13 on: October 29, 2024, 02:49:57 am »
I didn’t even know that constref existed before.
https://wiki.freepascal.org/Constref
 Is this is for multi threaded programs?

I’ve never used default before I probably should.
https://wiki.freepascal.org/Default

That is some interesting code  :)
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

440bx

  • Hero Member
  • *****
  • Posts: 4735
Re: Strange bugs with Advanced Records
« Reply #14 on: October 29, 2024, 04:27:53 am »
I didn’t even know that constref existed before.
https://wiki.freepascal.org/Constref
 Is this is for multi threaded programs?
"constref" has nothing to do with multi-threaded programs.  It is a way to tell the compiler to pass the parameter by reference and that in spite of it being passed by reference, the parameter cannot be modified, i.e, is constant.  "constref" = constant by reference (reference = pass the address of the structure.)

It is normally used when passing large data structures that the routine only needs to read (will not modify.)  For instance, passing an array of 1,000,000 elements to a function/procedure is best done as "constref", otherwise the compiler will create a _copy_ of the array on the stack (if neither "var" nor "const" nor "constref" are specified as parameter modifiers.)

Note that the documentation states that the programmer should _not_ assume that a "const" parameter will be passed by reference, which is correct because if the parameter fits in a register then it can simply be placed in a register, whereas if the parameter is a structured type then "const" will cause its address to be passed to the routine.  "constref" makes it clear that it will always be passed by reference (unlike "const" which may or may not pass by reference depending on the size of the argument.)

HTH.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018